Railway Operation Simulator  v2.10.0
A railway simulator for Windows
TrackUnit.cpp
Go to the documentation of this file.
1 // TrackUnit.cpp
2 /*
3  BEWARE OF COMMENTS in .cpp files: they were accurate when written but have
4  sometimes been overtaken by changes and not updated
5  Comments in .h files are believed to be accurate and up to date
6 
7  This is a source code file for "railway.exe", a railway operation
8  simulator, written originally in Borland C++ Builder 4 Professional with
9  later updates in Embarcadero C++Builder 10.2.
10  Copyright (C) 2010 Albert Ball [original development]
11 
12  This program is free software: you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25 // ---------------------------------------------------------------------------
26 #include <Classes.hpp>
27 #include <Controls.hpp>
28 #include <StdCtrls.hpp>
29 #include <Forms.hpp>
30 #include <Buttons.hpp>
31 #include <ExtCtrls.hpp>
32 #include <Menus.hpp>
33 #include <Dialogs.hpp>
34 #include <Graphics.hpp>
35 #include <ComCtrls.hpp>
36 #include <fstream>
37 #include <vector>
38 #include <algorithm> //for std::find
39 #include <vcl.h>
40 
41 #pragma hdrstop
42 
43 #include "TrackUnit.h"
44 #include "Utilities.h"
45 // #include "DisplayUnit.h" included in header file
46 #include "GraphicUnit.h"
47 #include "TextUnit.h"
48 #include "TrainUnit.h"
49 
50 #pragma package(smart_init)
51 // ---------------------------------------------------------------------------
52 
55 
56 // ---------------------------------------------------------------------------
57 
58 // FIXED TRACK :-
59 
60 // Constructor to build TrackPieces from array
61 
62 TFixedTrackPiece::TFixedTrackPiece(int SpeedTagVal, TTrackType TrackTypeVal, int LkVal[4], TConfiguration ConfigVal[4], Graphics::TBitmap* GraphicPtrVal,
63  Graphics::TBitmap* SmallGraphicPtrVal) : SpeedTag(SpeedTagVal), TrackType(TrackTypeVal), GraphicPtr(GraphicPtrVal), SmallGraphicPtr(SmallGraphicPtrVal)
64 {
65  for(int x = 0; x < 4; x++)
66  {
67  Link[x] = LkVal[x];
68  Config[x] = ConfigVal[x];
69  }
70 // NamedLocationElements 76, 77, 78, 79, 96, 129, 130, 131, 145 & 146 (platforms, concourses, footcrossings & named non-station locations)
71  FixedNamedLocationElement = false; // underpasses (144 & 145 added at v2.3.1
72  if(SpeedTagVal == 76)
73  {
75  }
76  else if(SpeedTagVal == 77)
77  {
79  }
80  else if(SpeedTagVal == 78)
81  {
83  }
84  else if(SpeedTagVal == 79)
85  {
87  }
88  else if(SpeedTagVal == 96)
89  {
91  }
92  else if(SpeedTagVal == 129)
93  {
95  }
96  else if(SpeedTagVal == 130)
97  {
99  }
100  else if(SpeedTagVal == 131)
101  {
103  }
104  else if(SpeedTagVal == 145)
105  {
107  }
108  else if(SpeedTagVal == 146)
109  {
111  }
112 }
113 
114 // ---------------------------------------------------------------------------
115 
116 TFixedTrackPiece::TFixedTrackPiece() : SpeedTag(0), TrackType(Erase), GraphicPtr(RailGraphics->bmSolidBgnd), SmallGraphicPtr(RailGraphics->smSolidBgnd),
117  FixedNamedLocationElement(false) // default values
118 {
119  for(int x = 0; x < 4; x++)
120  {
121  Link[x] = -1; // -1 & NotSet are the markers for 'unused' respectively
122  Config[x] = NotSet;
123  }
124 }
125 
126 // ---------------------------------------------------------------------------
127 void TFixedTrackPiece::PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
128 {
129  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotFixedTrackElement," + AnsiString(HLocInput) + "," +
130  AnsiString(VLocInput));
131  Display->PlotOutput(33, HLocInput * 16, VLocInput * 16, GraphicPtr);
132  Utilities->CallLogPop(1331);
133 }
134 
135 // ---------------------------------------------------------------------------
136 
137 // VARIABLE TRACK :-
138 
139 // ---------------------------------------------------------------------------
140 
142 {
143  if((this->HLoc == RHElement.HLoc) && (this->VLoc == RHElement.VLoc) && (this->SpeedTag == RHElement.SpeedTag))
144  {
145  return(true);
146  }
147  else
148  {
149  return(false);
150  }
151 }
152 
153 // ---------------------------------------------------------------------------
154 
156 {
157  if((this->HLoc != RHElement.HLoc) || (this->VLoc != RHElement.VLoc) || (this->SpeedTag != RHElement.SpeedTag))
158  {
159  return(true);
160  }
161  else
162  {
163  return(false);
164  }
165 }
166 
167 // ---------------------------------------------------------------------------
168 
170 // 'Variable' in the sense that element might be striped or non-striped
171 {
172  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotVariableTrackElement");
173  Graphics::TBitmap *GraphicOutput = GraphicPtr;
174 
175  if(LocationName == "")
176  {
177  switch(SpeedTag)
178  {
179  case 76: // t platform
180  GraphicOutput = RailGraphics->gl76Striped;
181  break;
182 
183  case 77: // h platform
184  GraphicOutput = RailGraphics->bm77Striped;
185  break;
186 
187  case 78: // v platform
188  GraphicOutput = RailGraphics->bm78Striped;
189  break;
190 
191  case 79: // r platform
192  GraphicOutput = RailGraphics->gl79Striped;
193  break;
194 
195  case 96: // concourse
196  GraphicOutput = RailGraphics->ConcourseStriped;
197  break;
198 
199  case 129: // v footbridge
200  GraphicOutput = RailGraphics->gl129Striped;
201  break;
202 
203  case 130: // h footbridge
204  GraphicOutput = RailGraphics->gl130Striped;
205  break;
206 
207  case 131: // non-station named loc
208  GraphicOutput = RailGraphics->bmNameStriped;
209  break;
210 
211  case 145: // v underpass
212  GraphicOutput = RailGraphics->gl145Striped;
213  break;
214 
215  case 146: // h underpass
216  GraphicOutput = RailGraphics->gl146Striped;
217  break;
218 
219  default:
220  GraphicOutput = GraphicPtr;
221  break;
222  }
223  }
224  Disp->PlotOutput(34, HLoc * 16, VLoc * 16, GraphicOutput);
225  Utilities->CallLogPop(1332);
226 }
227 
228 // ---------------------------------------------------------------------------
229 
230 AnsiString TTrackElement::LogTrack(int Caller) const
231 // for debugging when passes as a call parameter
232 {
233  AnsiString LogString = "TrkEl:-," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," +
234  AnsiString(TrainIDOnBridgeTrackPos01) + "," + AnsiString(TrainIDOnBridgeTrackPos23) + ",EndTrkEl,";
235 
236  return(LogString);
237 }
238 
239 // ---------------------------------------------------------------------------
240 
241 bool TMapComp:: operator()(const THVPair& lower, const THVPair& higher) const // HLoc VLoc
242 {
243  if(lower.second < higher.second)
244  {
245  return(true);
246  }
247  else if(lower.second > higher.second)
248  {
249  return(false);
250  }
251  else if(lower.second == higher.second)
252  {
253  if(lower.first < higher.first)
254  {
255  return(true);
256  }
257  }
258  return(false);
259 }
260 
261 // ---------------------------------------------------------------------------
262 // PrefDirElement Functions
263 // ---------------------------------------------------------------------------
264 
265 TPrefDirElement::TPrefDirElement(TTrackElement ElementIn, int ELinkIn, int ELinkPosIn, int XLinkIn, int XLinkPosIn, int TrackVectorPositionIn)
266  : TTrackElement(ElementIn), ELink(ELinkIn), ELinkPos(ELinkPosIn), XLink(XLinkIn), XLinkPos(XLinkPosIn), TrackVectorPosition(TrackVectorPositionIn),
267  CheckCount(9), IsARoute(false), AutoSignals(false), PrefDirRoute(false)
268 {
269  if(!EntryExitNumber())
270  {
271  throw Exception("EXNumber failure in TPrefDirElement constructor");
272  }
275 }
276 
277 // ---------------------------------------------------------------------------
278 
279 AnsiString TPrefDirElement::LogPrefDir() const
280 // for debugging when passed as a call parameter
281 {
282  AnsiString LogString = "PthEl:-," + AnsiString(ELink) + "," + AnsiString(ELinkPos) + "," + AnsiString(XLink) + "," + AnsiString(XLinkPos) + "," +
283  AnsiString(EXNumber) + "," + AnsiString(TrackVectorPosition) + "," + AnsiString((short)AutoSignals) + "," + AnsiString((short)PrefDirRoute) +
284  ",ElementID," + AnsiString(ElementID) + "," + LocationName + "," + AnsiString(TrainIDOnElement) + "," + AnsiString(TrainIDOnBridgeTrackPos01) + "," +
285  AnsiString(TrainIDOnBridgeTrackPos23);
286 
287 // Track->TrackElementAt(73, TrackVectorPosition).LogTrack(12);
288  return(LogString);
289 }
290 
291 // ---------------------------------------------------------------------------
292 
293 bool TPrefDirElement::EntryExitNumber() // true for valid number
294 /*
295  Computes a number corresponding to ELink & Xlink if set, or to the entry and exit link values for the track
296  at Link[0] and Link[1], or, if ELink or XLink not set, and a complex (4-entry) element, return false for error message.
297  This should be OK because only elements for which ELink & XLink not set are PrefDir/route start elements and leading points
298  as temporary end of PrefDir, and in both cases this function is not called as the direction is not displayed for these elements.
299  Uses simple links between any 2 entry & exit points for use in displaying PrefDir or route graphics, or original graphic during
300  route flashing. Should only be called when ELink & XLink set, or when ELinkPos & XLinkPos set deliberately from a
301  TTrackElement during route setting functions. If a bridge then an additional check is made in case the graphic needed
302  corresponds to an undebridge, i.e a gap needed between entry and exit. In this case the EXNumber is increased by
303  16 so as to be unique. Returns true if valid and sets EXNumber to the selected value.
304 */
305 
306 {
307  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EntryExitNumber");
308  int EXArray[16][2] =
309  {{4, 6}, {2, 8}, // horizontal & vertical
310  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
311  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
312  {1, 9}, {3, 7}}; // forward & reverse diagonals
313 
314  int EXNum = -1;
315  int Entry, Exit;
316 
317  if(ELink > -1)
318  {
319  Entry = ELink; // pick up simple elements even if ELink &/or XLink not set, as no ambiguity
320  }
321  else if(Link[2] == -1)
322  {
323  Entry = Link[0];
324  }
325  else
326  {
327  Utilities->CallLogPop(122);
328  return(false);
329  }
330  if(XLink > -1)
331  {
332  Exit = XLink;
333  }
334  else if(Link[2] == -1)
335  {
336  Exit = Link[1];
337  }
338  else
339  {
340  Utilities->CallLogPop(123);
341  return(false);
342  }
343  for(int x = 0; x < 16; x++)
344  {
345  if(((Entry == EXArray[x][0]) && (Exit == EXArray[x][1])) || ((Entry == EXArray[x][1]) && (Exit == EXArray[x][0]))) //added extra brackets round && segments at v2.9.1
346  {
347  EXNum = x;
348  }
349  }
350  if(EXNum == -1)
351  {
352  Utilities->CallLogPop(124);
353  return(false);
354  }
355  int BrNum = -1;
356 
357 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
358  the graphic for each of which is different because of the shape of the overbridge. The basic
359  entry/exit value is computed above, and this used to select only from elements with that entry/exit
360  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
361  int BrEXArray[24][2] = {
362  {4,6},{2,8},{1,9},{3,7},
363  {1,9},{3,7},{1,9},{3,7},
364  {2,8},{4,6},{2,8},{4,6}
365 */
366 
367  if(TrackType == Bridge)
368  {
369  if(EXNum == 1)
370  {
371  if(SpeedTag == 49)
372  {
373  BrNum = 1 + 16;
374  }
375  else if(SpeedTag == 54)
376  {
377  BrNum = 8 + 16;
378  }
379  else if(SpeedTag == 55)
380  {
381  BrNum = 10 + 16;
382  }
383  }
384  else if(EXNum == 0)
385  {
386  if(SpeedTag == 48)
387  {
388  BrNum = 0 + 16;
389  }
390  else if(SpeedTag == 58)
391  {
392  BrNum = 11 + 16;
393  }
394  else if(SpeedTag == 59)
395  {
396  BrNum = 9 + 16;
397  }
398  }
399  else if(EXNum == 14)
400  {
401  if(SpeedTag == 50)
402  {
403  BrNum = 2 + 16;
404  }
405  else if(SpeedTag == 52)
406  {
407  BrNum = 4 + 16;
408  }
409  else if(SpeedTag == 57)
410  {
411  BrNum = 6 + 16;
412  }
413  }
414  else if(EXNum == 15)
415  {
416  if(SpeedTag == 51)
417  {
418  BrNum = 3 + 16;
419  }
420  else if(SpeedTag == 53)
421  {
422  BrNum = 7 + 16;
423  }
424  else if(SpeedTag == 56)
425  {
426  BrNum = 5 + 16;
427  }
428  }
429  }
430  if(BrNum == -1)
431  {
432  EXNumber = EXNum;
433  }
434  else
435  {
436  EXNumber = BrNum;
437  }
438  Utilities->CallLogPop(125);
439  return(true);
440 }
441 
442 // ---------------------------------------------------------------------------
443 
445 /*
446  This is the basic track graphic for use in plotting the original graphic during route flashing.
447  Enter with all set apart from EXGraphic & EntryDirectionGraphic
448 */
449 {
450  if(SpeedTag == 64)
451  {
452  return(RailGraphics->LinkGraphicsPtr[16]); // intercept diagonal buffers
453 
454  }
455  if(SpeedTag == 65)
456  {
457  return(RailGraphics->LinkGraphicsPtr[17]);
458  }
459  if(SpeedTag == 66)
460  {
461  return(RailGraphics->LinkGraphicsPtr[18]);
462  }
463  if(SpeedTag == 67)
464  {
465  return(RailGraphics->LinkGraphicsPtr[19]);
466  }
467  if(SpeedTag == 80)
468  {
469  return(RailGraphics->LinkGraphicsPtr[20]); // intercept continuations
470 
471  }
472  if(SpeedTag == 81)
473  {
474  return(RailGraphics->LinkGraphicsPtr[21]);
475  }
476  if(SpeedTag == 82)
477  {
478  return(RailGraphics->LinkGraphicsPtr[22]);
479  }
480  if(SpeedTag == 83)
481  {
482  return(RailGraphics->LinkGraphicsPtr[23]);
483  }
484  if(SpeedTag == 84)
485  {
486  return(RailGraphics->LinkGraphicsPtr[24]);
487  }
488  if(SpeedTag == 85)
489  {
490  return(RailGraphics->LinkGraphicsPtr[25]);
491  }
492  if(SpeedTag == 86)
493  {
494  return(RailGraphics->LinkGraphicsPtr[26]);
495  }
496  if(SpeedTag == 87)
497  {
498  return(RailGraphics->LinkGraphicsPtr[27]);
499  }
500  if(SpeedTag == 129)
501  {
502  return(RailGraphics->LinkGraphicsPtr[28]); // intercept under footbridges
503 
504  }
505  if(SpeedTag == 130)
506  {
507  return(RailGraphics->LinkGraphicsPtr[29]);
508  }
509  if(XLinkPos == -1) // not set, could be first element or last element = leading point
510  {
511 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or
512 // Points & don't want to display these)
513  if(Link[2] != -1)
514  {
515  return(0); // i.e. complex element, don't display
516  }
517  else
518  {
519  if(!EntryExitNumber())
520  {
521  throw Exception("Error in EntryExitNumber 4");
522  }
523  else
524  {
526  }
527  }
528  }
529  if(EXNumber > 15) // underbridge
530  {
531  return(RailGraphics->BridgeGraphicsPtr[EXNumber - 16]);
532  }
533  else
534  {
536  }
537 }
538 
539 // ---------------------------------------------------------------------------
540 
542 /*
543  As above but for PrefDir graphics.
544 */
545 {
546  if(SpeedTag == 64)
547  {
548  return(RailGraphics->LinkPrefDirGraphicsPtr[16]); // intercept diagonal buffers
549 
550  }
551  if(SpeedTag == 65)
552  {
554  }
555  if(SpeedTag == 66)
556  {
558  }
559  if(SpeedTag == 67)
560  {
562  }
563  if(SpeedTag == 80)
564  {
565  return(RailGraphics->LinkPrefDirGraphicsPtr[20]); // intercept continuations
566 
567  }
568  if(SpeedTag == 81)
569  {
571  }
572  if(SpeedTag == 82)
573  {
575  }
576  if(SpeedTag == 83)
577  {
579  }
580  if(SpeedTag == 84)
581  {
583  }
584  if(SpeedTag == 85)
585  {
587  }
588  if(SpeedTag == 86)
589  {
591  }
592  if(SpeedTag == 87)
593  {
595  }
596  if(SpeedTag == 129)
597  {
598  return(RailGraphics->LinkPrefDirGraphicsPtr[28]); // intercept under footbridges
599 
600  }
601  if(SpeedTag == 130)
602  {
604  }
605  if(XLinkPos == -1) // not set, could be first element or last element = leading point
606  {
607 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
608  if(Link[2] != -1)
609  {
610  return(0); // i.e. complex element, don't display
611  }
612  else
613  {
614  if(!EntryExitNumber())
615  {
616  throw Exception("Error in EntryExitNumber 5");
617  }
618  else
619  {
621  }
622  }
623  }
624  if(EXNumber > 15) // underbridge
625  {
627  }
628  else
629  {
631  }
632 }
633 
634 // ---------------------------------------------------------------------------
635 
636 Graphics::TBitmap *TPrefDirElement::GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
637 /*
638  As above but for route graphics.
639 */
640 {
641  if(!AutoSigsFlag && !PrefDirRoute)
642  {
643  if(SpeedTag == 64)
644  {
645  return(RailGraphics->LinkNonSigRouteGraphicsPtr[16]); // intercept diagonal buffers
646 
647  }
648  if(SpeedTag == 65)
649  {
651  }
652  if(SpeedTag == 66)
653  {
655  }
656  if(SpeedTag == 67)
657  {
659  }
660  if(SpeedTag == 80)
661  {
662  return(RailGraphics->LinkNonSigRouteGraphicsPtr[20]); // intercept continuations
663 
664  }
665  if(SpeedTag == 81)
666  {
668  }
669  if(SpeedTag == 82)
670  {
672  }
673  if(SpeedTag == 83)
674  {
676  }
677  if(SpeedTag == 84)
678  {
680  }
681  if(SpeedTag == 85)
682  {
684  }
685  if(SpeedTag == 86)
686  {
688  }
689  if(SpeedTag == 87)
690  {
692  }
693  if(SpeedTag == 129)
694  {
695  return(RailGraphics->LinkNonSigRouteGraphicsPtr[28]); // intercept under footbridges
696 
697  }
698  if(SpeedTag == 130)
699  {
701  }
702  if(XLinkPos == -1) // not set, could be first element or last element = leading point
703  {
704  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
705  if(Link[2] != -1)
706  {
707  return(0); // i.e. complex element, don't display
708  }
709  else
710  {
711  if(!EntryExitNumber())
712  {
713  throw Exception("Error in EntryExitNumber 6");
714  }
715  else
716  {
718  }
719  }
720  }
721  if(EXNumber > 15) // underbridge
722  {
724  }
725  else
726  {
728  }
729  }
730 
731  else if(!AutoSigsFlag && PrefDirRoute)
732  {
733  if(SpeedTag == 64)
734  {
735  return(RailGraphics->LinkSigRouteGraphicsPtr[16]); // intercept diagonal buffers
736 
737  }
738  if(SpeedTag == 65)
739  {
741  }
742  if(SpeedTag == 66)
743  {
745  }
746  if(SpeedTag == 67)
747  {
749  }
750  if(SpeedTag == 80)
751  {
752  return(RailGraphics->LinkSigRouteGraphicsPtr[20]); // intercept continuations
753 
754  }
755  if(SpeedTag == 81)
756  {
758  }
759  if(SpeedTag == 82)
760  {
762  }
763  if(SpeedTag == 83)
764  {
766  }
767  if(SpeedTag == 84)
768  {
770  }
771  if(SpeedTag == 85)
772  {
774  }
775  if(SpeedTag == 86)
776  {
778  }
779  if(SpeedTag == 87)
780  {
782  }
783  if(SpeedTag == 129)
784  {
785  return(RailGraphics->LinkSigRouteGraphicsPtr[28]); // intercept under footbridges
786 
787  }
788  if(SpeedTag == 130)
789  {
791  }
792  if(XLinkPos == -1) // not set, could be first element or last element = leading point
793  {
794  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
795  if(Link[2] != -1)
796  {
797  return(0); // i.e. complex element, don't display
798  }
799  else
800  {
801  if(!EntryExitNumber())
802  {
803  throw Exception("Error in EntryExitNumber 10");
804  }
805  else
806  {
808  }
809  }
810  }
811  if(EXNumber > 15) // underbridge
812  {
814  }
815  else
816  {
818  }
819  }
820 
821  else
822  {
823  if(SpeedTag == 64)
824  {
825  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
826 
827  }
828  if(SpeedTag == 65)
829  {
831  }
832  if(SpeedTag == 66)
833  {
835  }
836  if(SpeedTag == 67)
837  {
839  }
840  if(SpeedTag == 80)
841  {
842  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
843 
844  }
845  if(SpeedTag == 81)
846  {
848  }
849  if(SpeedTag == 82)
850  {
852  }
853  if(SpeedTag == 83)
854  {
856  }
857  if(SpeedTag == 84)
858  {
860  }
861  if(SpeedTag == 85)
862  {
864  }
865  if(SpeedTag == 86)
866  {
868  }
869  if(SpeedTag == 87)
870  {
872  }
873  if(SpeedTag == 129)
874  {
875  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
876 
877  }
878  if(SpeedTag == 130)
879  {
881  }
882  if(XLinkPos == -1) // not set, could be first element or last element = leading point
883  {
884  // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
885  if(Link[2] != -1)
886  {
887  return(0); // i.e. complex element, don't display
888  }
889  else
890  {
891  if(!EntryExitNumber())
892  {
893  throw Exception("Error in EntryExitNumber 11");
894  }
895  else
896  {
898  }
899  }
900  }
901  if(EXNumber > 15) // underbridge
902  {
904  }
905  else
906  {
908  }
909  }
910 }
911 
912 // ---------------------------------------------------------------------------
913 
915 /*
916  As above but for route flashing graphics. (Disused - now combined with above)
917 */
918 {
919  if(SpeedTag == 64)
920  {
921  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]); // intercept diagonal buffers
922 
923  }
924  if(SpeedTag == 65)
925  {
927  }
928  if(SpeedTag == 66)
929  {
931  }
932  if(SpeedTag == 67)
933  {
935  }
936  if(SpeedTag == 80)
937  {
938  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]); // intercept continuations
939 
940  }
941  if(SpeedTag == 81)
942  {
944  }
945  if(SpeedTag == 82)
946  {
948  }
949  if(SpeedTag == 83)
950  {
952  }
953  if(SpeedTag == 84)
954  {
956  }
957  if(SpeedTag == 85)
958  {
960  }
961  if(SpeedTag == 86)
962  {
964  }
965  if(SpeedTag == 87)
966  {
968  }
969  if(SpeedTag == 129)
970  {
971  return(RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]); // intercept under footbridges
972 
973  }
974  if(SpeedTag == 130)
975  {
977  }
978  if(XLinkPos == -1) // not set, could be first element or last element = leading point
979  {
980 // check if just a simple one in & one out & if so set graphic (otherwise Bridge, Crossover or Points)
981  if(Link[2] != -1)
982  {
983  return(0); // i.e. complex element, don't display
984  }
985  else
986  {
987  if(!EntryExitNumber())
988  {
989  throw Exception("Error in EntryExitNumber 7");
990  }
991  else
992  {
994  }
995  }
996  }
997  if(EXNumber > 15) // underbridge
998  {
1000  }
1001  else
1002  {
1004  }
1005 }
1006 
1007 // ---------------------------------------------------------------------------
1008 
1010 /*
1011  Get PrefDir direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1012 */
1013 {
1014  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1015  {
1017  }
1018  else
1019  {
1020  throw Exception("Error in EntryExitNumber 8");
1021  }
1022 }
1023 
1024 // ---------------------------------------------------------------------------
1025 
1026 Graphics::TBitmap *TPrefDirElement::GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
1027 /*
1028  Get route direction graphic. Enter with all set apart from EXGraphic & EntryDirectionGraphic
1029 */
1030 {
1031  if((ELink > 0) && (ELink < 10) && (ELink != 5))
1032  {
1033  if(!AutoSigsFlag && !PrefDirRoute)
1034  {
1036  }
1037  else if(!AutoSigsFlag && PrefDirRoute)
1038  {
1040  }
1041  else
1042  {
1044  }
1045  }
1046  else
1047  {
1048  throw Exception("Error in EntryExitNumber 9");
1049  }
1050 }
1051 
1052 // ---------------------------------------------------------------------------
1053 
1055 /*
1056  Set == operator when TrackVectorPosition, ELink & XLink all same
1057 */
1058 {
1059  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1060  {
1061  return(true);
1062  }
1063  else
1064  {
1065  return(false);
1066  }
1067 }
1068 
1069 // ---------------------------------------------------------------------------
1070 
1072 /*
1073  Set != operator when any of TrackVectorPosition, ELink or XLink different
1074 */
1075 {
1076  if((this->TrackVectorPosition == RHElement.TrackVectorPosition) && (this->ELink == RHElement.ELink) && (this->XLink == RHElement.XLink))
1077  {
1078  return(false);
1079  }
1080  else
1081  {
1082  return(true);
1083  }
1084 }
1085 
1086 // ---------------------------------------------------------------------------
1087 // Track functions
1088 // ---------------------------------------------------------------------------
1089 
1090 // ---------------------------------------------------------------------------
1091 
1092 TTrack::TActiveLevelCrossing::TActiveLevelCrossing()
1093 {
1094  TypeOfRoute = 0;
1095  ReducedTimePenalty = false;
1096  BarrierState = Up;
1097  ChangeDuration = 0.0;
1098  BaseElementSpeedTag = 1;
1099  HLoc = 0;
1100  VLoc = 0;
1101  StartTime = TDateTime(0);
1102 }
1103 
1104 // ---------------------------------------------------------------------------
1105 
1107 {
1108 // CurrentSpeedButtonTag = 0; //not assigned yet
1109 
1110  HLocMin = 2000000000;
1111  VLocMin = 2000000000;
1112  HLocMax = -2000000000;
1113  VLocMax = -2000000000;
1114  SkipLocationNameMultiMapCheck = false; // new at v2.2.0, false is default value
1115  CopyFlag = false; // only true for copying, so names aren't copied
1116  AnsiString NL = '\n';
1117 
1118  RouteFailMessage = "Unable to set a route:" + NL + NL + "it may be unreachable; " + NL + NL +
1119  "reachable but with too many different directions leading away from the start point - set some points on the route required; " + NL + NL +
1120  "blocked by a train, another route or a changing level crossing; " + NL + NL +
1121  "or invalid - possibly due to a preferred direction mismatch, or a missed signal in a blue route or green route restricted to consecutive signals.";
1122 
1127 
1128  int InternalLinkCheckArray[9][2] =
1129  {{1, 9}, {4, 6}, {7, 3}, {2, 8}, {0, 0}, {8, 2}, {3, 7}, {6, 4}, {9, 1}};
1130 
1131 /* array of valid link values for 'old' location and 'new' location, where
1132  array number = (((Hnew - Hold)+1)*3) + ((Vnew - Vold)+1) */
1133 
1134  for(int x = 0; x < 9; x++)
1135  {
1136  for(int y = 0; y < 2; y++)
1137  {
1138  LinkCheckArray[x][y] = InternalLinkCheckArray[x][y];
1139  }
1140  }
1141 
1142 // Platform and default track element values
1143  TopPlatAllowed << 1 << 9 << 10 << 30 << 31 << 60 << 61 << 68 << 69 << 77 << 125 << 126 << 129 << 145;
1144 // top & bot sigs, straights, straight points, buffers, signal, vert footcrossing, bot plat
1145  BotPlatAllowed << 1 << 7 << 8 << 28 << 29 << 60 << 61 << 68 << 69 << 76 << 125 << 126 << 129 << 145;
1146  LeftPlatAllowed << 2 << 12 << 14 << 33 << 35 << 62 << 63 << 70 << 71 << 79 << 127 << 128 << 130 << 146;
1147  RightPlatAllowed << 2 << 11 << 13 << 32 << 34 << 62 << 63 << 70 << 71 << 78 << 127 << 128 << 130 << 146;
1148  NameAllowed << 1 << 2 << 3 << 4 << 5 << 6 << 20 << 21 << 22 << 23 << 24 << 25 << 26 << 27 // disallow diagonals, points, crossovers, bridges, gaps,
1149  << 60 << 61 << 62 << 63 << 68 << 69 << 70 << 71 << 80 << 81 << 82 << 83 << 125 << 126 << 127 << 128; // diag continuations, diag buffers, footcrossings (diagonals may be OK
1150  // but as can't link diagonal locations would need solid blocks to allow linkage & that would look untidy except for single
1151  // elements, & can always use straights so leave out.) Allow horiz & vert signals as from v2.6.0
1152  LevelCrossingAllowed << 1 << 2; // only allow on straight tracks without direction markers
1153 // Note platforms not allowed at continuations, but named non-station locations OK, though not allowed in timetables
1154 
1155  int HVArray[10][2] =
1156  {{0, 0}, {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
1157 
1158  for(int x = 0; x < 10; x++)
1159  {
1160  for(int y = 0; y < 2; y++)
1161  {
1162  LinkHVArray[x][y] = HVArray[x][y];
1163  }
1164  }
1165  TrackFinished = false;
1166 // DistancesSet = false;
1167 
1168  TSigElement TempSigTable[40] = // original four aspect
1169  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1170  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1171 
1172  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1173  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1174 
1177 
1178  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1179  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1180 
1181  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1182  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1183  {75, 4, RailGraphics->gl75}};
1184 
1185  for(int x = 0; x < 40; x++)
1186  {
1187  SigTable[x] = TempSigTable[x];
1188  }
1189 
1190  TSigElement TempSigTableThreeAspect[40] =
1191  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1192  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1193 
1194  {68, 1, RailGraphics->bm68yellow}, {69, 1, RailGraphics->bm69yellow}, {70, 1, RailGraphics->bm70yellow}, {71, 1, RailGraphics->bm71yellow},
1195  {72, 1, RailGraphics->bm72yellow}, {73, 1, RailGraphics->bm73yellow}, {74, 1, RailGraphics->bm74yellow}, {75, 1, RailGraphics->bm75yellow},
1196 
1197  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1198  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1199 
1200  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1201  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1202 
1203  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1204  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1205  {75, 4, RailGraphics->gl75}};
1206 
1207  for(int x = 0; x < 40; x++)
1208  {
1209  SigTableThreeAspect[x] = TempSigTableThreeAspect[x];
1210  }
1211 
1212  TSigElement TempSigTableTwoAspect[40] =
1213  {{68, 0, RailGraphics->gl68}, {69, 0, RailGraphics->gl69}, {70, 0, RailGraphics->gl70}, {71, 0, RailGraphics->gl71}, {72, 0, RailGraphics->gl72},
1214  {73, 0, RailGraphics->bm73}, {74, 0, RailGraphics->bm74}, {75, 0, RailGraphics->gl75},
1215 
1216  {68, 1, RailGraphics->bm68green}, {69, 1, RailGraphics->bm69green}, {70, 1, RailGraphics->bm70green}, {71, 1, RailGraphics->bm71green},
1217  {72, 1, RailGraphics->bm72green}, {73, 1, RailGraphics->bm73green}, {74, 1, RailGraphics->bm74green}, {75, 1, RailGraphics->bm75green},
1218 
1219  {68, 2, RailGraphics->bm68green}, {69, 2, RailGraphics->bm69green}, {70, 2, RailGraphics->bm70green}, {71, 2, RailGraphics->bm71green},
1220  {72, 2, RailGraphics->bm72green}, {73, 2, RailGraphics->bm73green}, {74, 2, RailGraphics->bm74green}, {75, 2, RailGraphics->bm75green},
1221 
1222  {68, 3, RailGraphics->bm68green}, {69, 3, RailGraphics->bm69green}, {70, 3, RailGraphics->bm70green}, {71, 3, RailGraphics->bm71green},
1223  {72, 3, RailGraphics->bm72green}, {73, 3, RailGraphics->bm73green}, {74, 3, RailGraphics->bm74green}, {75, 3, RailGraphics->bm75green},
1224 
1225  {68, 4, RailGraphics->gl68}, {69, 4, RailGraphics->gl69}, // Attr 4 disused but leave in case re-instate
1226  {70, 4, RailGraphics->gl70}, {71, 4, RailGraphics->gl71}, {72, 4, RailGraphics->gl72}, {73, 4, RailGraphics->bm73}, {74, 4, RailGraphics->bm74},
1227  {75, 4, RailGraphics->gl75}};
1228 
1229  for(int x = 0; x < 40; x++)
1230  {
1231  SigTableTwoAspect[x] = TempSigTableTwoAspect[x];
1232  }
1233 
1234  TSigElement TempSigTableGroundSignal[40] =
1238 
1242 
1246 
1250 
1251  {68, 4, RailGraphics->bm68grounddblred}, {69, 4, RailGraphics->bm69grounddblred}, // Attr 4 disused but leave in case re-instate
1254 
1255  for(int x = 0; x < 40; x++)
1256  {
1257  SigTableGroundSignal[x] = TempSigTableGroundSignal[x];
1258  }
1259 
1260 /*
1261  Named Location Arrays: Set out the adjacent positions and tracktypes that are accepted as valid connections for
1262  a single location. These are as follows:-
1263  Directly Adjacent = up, down, left or right - NOT diagonal.
1264  There are two separate groups, platforms, concourses & footcrossings (providing the crossing part touches or overlaps the other relevant
1265  named location) all link with each other providing directly adjacent, but not to NamedNonStationLocations.
1266  NamedNonStationLocation link to other NamedNonStationLocations providing directly adjacent, but not to anything else.
1267 
1268  //t 76
1269  //b 77
1270  //l 78
1271  //r 79
1272  //c 96
1273  //v fb 129
1274  //h fb 130
1275  //v underpass 145
1276  //h underpass 146
1277  //n 131
1278 */
1279 
1280  int Tag76[25][3] =
1281  {{-1, 0, 96}, // c top plat
1282  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1283  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1284  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {0, 0, 77}, {-1, 0, 78}, // l
1285  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1286  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, -1, 129}, // v fb
1287  {0, 0, 129}, {0, -1, 145}, // v up
1288  {0, 0, 145}};
1289 
1290  for(int x = 0; x < 25; x++)
1291  {
1292  for(int y = 0; y < 3; y++)
1293  {
1294  Tag76Array[x][y] = Tag76[x][y];
1295  }
1296  }
1297 
1298  int Tag77[25][3] =
1299  {{-1, 0, 96}, // c bot plat
1300  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1301  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {0, 0, 76}, {-1, 0, 77}, // b
1302  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1303  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1304  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1305  {0, 0, 129}, {0, 1, 145}, // v up
1306  {0, 0, 145}};
1307 
1308  for(int x = 0; x < 25; x++)
1309  {
1310  for(int y = 0; y < 3; y++)
1311  {
1312  Tag77Array[x][y] = Tag77[x][y];
1313  }
1314  }
1315 
1316  int Tag78[25][3] =
1317  {{-1, 0, 96}, // c left plat
1318  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1319  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1320  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1321  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1322  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 0, 79}, {-1, 0, 130}, // h fb
1323  {0, 0, 130}, {-1, 0, 146}, // h up
1324  {0, 0, 146}};
1325 
1326  for(int x = 0; x < 25; x++)
1327  {
1328  for(int y = 0; y < 3; y++)
1329  {
1330  Tag78Array[x][y] = Tag78[x][y];
1331  }
1332  }
1333 
1334  int Tag79[25][3] =
1335  {{-1, 0, 96}, // c right plat
1336  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1337  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1338  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1339  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {0, 0, 78}, {-1, 0, 79}, // r
1340  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {1, 0, 130}, // h fb
1341  {0, 0, 130}, {1, 0, 146}, // h up
1342  {0, 0, 146}};
1343 
1344  for(int x = 0; x < 25; x++)
1345  {
1346  for(int y = 0; y < 3; y++)
1347  {
1348  Tag79Array[x][y] = Tag79[x][y];
1349  }
1350  }
1351 
1352  int Tag96[28][3] =
1353  {{-1, 0, 96}, // c //concourse
1354  {1, 0, 96}, {0, -1, 96}, {0, 1, 96}, {-1, 0, 76}, // t
1355  {1, 0, 76}, {0, -1, 76}, {0, 1, 76}, {-1, 0, 77}, // b
1356  {1, 0, 77}, {0, -1, 77}, {0, 1, 77}, {-1, 0, 78}, // l
1357  {1, 0, 78}, {0, -1, 78}, {0, 1, 78}, {-1, 0, 79}, // r
1358  {1, 0, 79}, {0, -1, 79}, {0, 1, 79}, {0, 1, 129}, // v fb
1359  {0, -1, 129}, {1, 0, 130}, // h fb
1360  {-1, 0, 130}, {0, 1, 145}, // v up
1361  {0, -1, 145}, {1, 0, 146}, // h up
1362  {-1, 0, 146}};
1363 
1364  for(int x = 0; x < 28; x++)
1365  {
1366  for(int y = 0; y < 3; y++)
1367  {
1368  Tag96Array[x][y] = Tag96[x][y];
1369  }
1370  }
1371 
1372  int Tag129[8][3] = // vert fb
1373  {{0, -1, 96}, // c
1374  {0, -1, 77}, // b
1375  {0, -1, 129}, // v fb
1376 
1377  {0, 1, 96}, // c
1378  {0, 1, 76}, // t
1379  {0, 1, 129}, // v fb
1380 
1381  {0, 0, 76}, // t
1382  {0, 0, 77}}; // b
1383 
1384  for(int x = 0; x < 8; x++)
1385  {
1386  for(int y = 0; y < 3; y++)
1387  {
1388  Tag129Array[x][y] = Tag129[x][y];
1389  }
1390  }
1391 
1392  int Tag145[8][3] = // vert up
1393  {{0, -1, 96}, // c
1394  {0, -1, 77}, // b
1395  {0, -1, 145}, // v fb
1396 
1397  {0, 1, 96}, // c
1398  {0, 1, 76}, // t
1399  {0, 1, 145}, // v fb
1400 
1401  {0, 0, 76}, // t
1402  {0, 0, 77}}; // b
1403 
1404  for(int x = 0; x < 8; x++)
1405  {
1406  for(int y = 0; y < 3; y++)
1407  {
1408  Tag145Array[x][y] = Tag145[x][y];
1409  }
1410  }
1411 
1412  int Tag130[8][3] = // hor fb
1413  {{-1, 0, 96}, // c
1414  {-1, 0, 79}, // r
1415  {-1, 0, 130}, // h fb
1416 
1417  {1, 0, 96}, // c
1418  {1, 0, 78}, // l
1419  {1, 0, 130}, // h fb
1420 
1421  {0, 0, 78}, // l
1422  {0, 0, 79}}; // r
1423 
1424  for(int x = 0; x < 8; x++)
1425  {
1426  for(int y = 0; y < 3; y++)
1427  {
1428  Tag130Array[x][y] = Tag130[x][y];
1429  }
1430  }
1431 
1432  int Tag146[8][3] = // hor up
1433  {{-1, 0, 96}, // c
1434  {-1, 0, 79}, // r
1435  {-1, 0, 146}, // h fb
1436 
1437  {1, 0, 96}, // c
1438  {1, 0, 78}, // l
1439  {1, 0, 146}, // h fb
1440 
1441  {0, 0, 78}, // l
1442  {0, 0, 79}}; // r
1443 
1444  for(int x = 0; x < 8; x++)
1445  {
1446  for(int y = 0; y < 3; y++)
1447  {
1448  Tag146Array[x][y] = Tag146[x][y];
1449  }
1450  }
1451 
1452  int Tag131[4][3] =
1453  {{-1, 0, 131}, // n
1454  {1, 0, 131}, {0, -1, 131}, {0, 1, 131}};
1455 
1456  for(int x = 0; x < 4; x++)
1457  {
1458  for(int y = 0; y < 3; y++)
1459  {
1460  Tag131Array[x][y] = Tag131[x][y];
1461  }
1462  }
1463 
1464  int InternalFlipArray[FirstUnusedSpeedTagNumber] =
1465  {
1466  0, 1, 2, 5, 6, 3, 4, 9, 10, 7, 8, 13, 14, 11, 12, 15, 16, 17, 19, 18, 22, 23, 20, 21, 26, 27, 24, 25, 30, 31, 28, 29, 34, 35, 32, 33, 38, 39, 36, 37, 42,
1467  43, 40, 41, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 60, 61, 63, 62, 66, 67, 64, 65, 68, 69, 71, 70, 74, 75, 72, 73, 77, 76, 78,
1468  79, 80, 81, 83, 82, 86, 87, 84, 85, 88, 89, 91, 90, 94, 95, 92, 93, 96, 99, 100, 97, 98, 103, 104, 101, 102, 106, 105, 109, 110, 107, 108, 113, 114,
1469  111, 112, 117, 118, 115, 116, 119, 120, 121, 123, 122, 124, 125, 126, 128, 127, 129, 130, 131, 134, 133, 132, 135, 139, 138, 137, 136, 143, 142, 141,
1470  140, 144, 145, 146
1471  };
1472 
1473  int InternalMirrorArray[FirstUnusedSpeedTagNumber] =
1474  {
1475  0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 15, 16, 17, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28, 31, 30, 33, 32, 35, 34, 37, 36, 39, 38, 41,
1476  40, 43, 42, 45, 44, 47, 46, 48, 49, 51, 50, 53, 52, 55, 54, 57, 56, 59, 58, 61, 60, 62, 63, 65, 64, 67, 66, 69, 68, 70, 71, 73, 72, 75, 74, 76, 77, 79,
1477  78, 81, 80, 82, 83, 85, 84, 87, 86, 89, 88, 90, 91, 93, 92, 95, 94, 96, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111,
1478  114, 113, 116, 115, 118, 117, 119, 120, 124, 122, 123, 121, 126, 125, 127, 128, 129, 130, 131, 132, 135, 134, 133, 137, 136, 139, 138, 142, 143, 140,
1479  141, 144, 145, 146
1480  };
1481 
1482  int InternalRotRightArray[FirstUnusedSpeedTagNumber] =
1483  {
1484  0, 2, 1, 4, 6, 3, 5, 14, 12, 13, 11, 7, 9, 8, 10, 15, 16, 17, 19, 18, 25, 27, 24, 26, 21, 23, 20, 22, 35, 33, 34, 32, 28, 30, 29, 31, 41, 43, 40, 42, 37,
1485  39, 36, 38, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 63, 62, 60, 61, 65, 67, 64, 66, 71, 70, 68, 69, 73, 75, 72, 74, 79, 78, 76,
1486  77, 83, 82, 80, 81, 85, 87, 84, 86, 91, 90, 88, 89, 93, 95, 92, 94, 96, 102, 104, 101, 103, 98, 100, 97, 99, 106, 105, 108, 110, 107, 109, 116, 118,
1487  115, 117, 112, 114, 111, 113, 120, 119, 122, 124, 121, 123, 127, 128, 126, 125, 130, 129, 131, 133, 134, 135, 132, 137, 138, 139, 136, 143, 142, 140,
1488  141, 144, 146, 145
1489  };
1490 
1491  int InternalRotLeftArray[FirstUnusedSpeedTagNumber] =
1492  {
1493  0, 2, 1, 5, 3, 6, 4, 11, 13, 12, 14, 10, 8, 9, 7, 15, 16, 17, 19, 18, 26, 24, 27, 25, 22, 20, 23, 21, 32, 34, 33, 35, 31, 29, 30, 28, 42, 40, 43, 41, 38,
1494  36, 39, 37, 46, 47, 44, 45, 49, 48, 51, 50, 56, 57, 58, 59, 52, 53, 54, 55, 62, 63, 61, 60, 66, 64, 67, 65, 70, 71, 69, 68, 74, 72, 75, 73, 78, 79, 77,
1495  76, 82, 83, 81, 80, 86, 84, 87, 85, 90, 91, 89, 88, 94, 92, 95, 93, 96, 103, 101, 104, 102, 99, 97, 100, 98, 106, 105, 109, 107, 110, 108, 117, 115,
1496  118, 116, 113, 111, 114, 112, 120, 119, 123, 121, 124, 122, 128, 127, 125, 126, 130, 129, 131, 135, 132, 133, 134, 139, 136, 137, 138, 142, 143, 141,
1497  140, 144, 146, 145
1498  };
1499 
1500  for(int x = 0; x < FirstUnusedSpeedTagNumber; x++)
1501  {
1502  FlipArray[x] = InternalFlipArray[x];
1503  MirrorArray[x] = InternalMirrorArray[x];
1504  RotRightArray[x] = InternalRotRightArray[x];
1505  RotLeftArray[x] = InternalRotLeftArray[x];
1506  }
1507 }
1508 
1509 // ---------------------------------------------------------------------------
1511 {
1512 // delete TrackVectorPtr;
1513 // delete FixedTrackArrayPtr;
1514  TTrack::TUserGraphicMap::iterator UGMIt = Track->UserGraphicMap.begin();
1515 
1516  while(UGMIt != Track->UserGraphicMap.end()) // delete all the TPictures in the map
1517  {
1518  delete UGMIt->second;
1519  UGMIt++;
1520  }
1521  delete GapFlashGreen;
1522  delete GapFlashRed;
1523  // all the rest are cleared by the relevant automatic destructors
1524 }
1525 
1526 // ---------------------------------------------------------------------------
1527 
1529 {
1530  Graphics::TBitmap *TrackImageArray[FirstUnusedSpeedTagNumber] =
1531  {
1532 // loc 0 not used, set to bmSolidBgnd
1536 // no 17 not used (was used for text in early phases), set to bmSolidBgnd
1556  };
1557 
1558  Graphics::TBitmap *SmallTrackImageArray[FirstUnusedSpeedTagNumber] =
1559  {
1560 // loc 0 not used, set to smSolidBgnd
1564 // no 17 not used (was used for text in early phases), set to smSolidBgnd
1583  RailGraphics->smLC, RailGraphics->sm129, RailGraphics->sm130 // use small footbridges for underpasses
1584  };
1585 
1586 // track types
1587  TTrackType TrackTypeArray[FirstUnusedSpeedTagNumber] =
1588  {
1589  Erase, // 1 0
1590  Simple, Simple, Simple, Simple, Simple, Simple, // 6 1-6
1591  Points, Points, Points, Points, Points, Points, Points, Points, // 8 7-14
1592  Crossover, Crossover, // 2 15-16
1593  Unused, // 17 (was for text in earlier development) //1 17
1596  Crossover, Crossover, Crossover, Crossover, // 4 44-47
1600  Platform, Platform, Platform, Platform, // 4 76-79
1603  Concourse, // 1 96
1606  Simple, Simple, Simple, Simple, // 4 125-128
1607  FootCrossing, FootCrossing, // 2 129-130
1608  NamedNonStationLocation, // 1 131
1609  Points, Points, Points, Points, Points, Points, Points, Points, // 8 132-139
1610  Simple, Simple, Simple, Simple, // 4 140-143
1611  LevelCrossing, // 1 144
1612  FootCrossing, FootCrossing // 2 145 & 146
1613  };
1614 
1615 // links
1616  int Links[FirstUnusedSpeedTagNumber][4] =
1617  {{-1, -1, -1, -1}, // erase element
1618  {4, 6, -1, -1}, {2, 8, -1, -1}, {6, 8, -1, -1}, {4, 8, -1, -1}, {2, 6, -1, -1}, {2, 4, -1, -1}, // simple
1619  {4, 6, 4, 2}, {6, 4, 6, 2}, {4, 6, 4, 8}, {6, 4, 6, 8}, {8, 2, 8, 4}, {8, 2, 8, 6}, {2, 8, 2, 4}, {2, 8, 2, 6}, // points
1620 // points always have links 0 & 2 = lead, link 1 = trailing straight, link 3 = trailing diverging
1621  {4, 6, 2, 8}, {1, 9, 3, 7}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1622  {-1, -1, -1, -1}, // unused
1623  {3, 7, -1, -1}, {1, 9, -1, -1}, {7, 6, -1, -1}, {4, 9, -1, -1}, {1, 6, -1, -1}, {4, 3, -1, -1}, {3, 8, -1, -1}, {1, 8, -1, -1}, {2, 9, -1, -1},
1624  {2, 7, -1, -1}, // simple
1625  {4, 6, 4, 3}, {6, 4, 6, 1}, {4, 6, 4, 9}, {6, 4, 6, 7}, {8, 2, 8, 1}, {8, 2, 8, 3}, {2, 8, 2, 7}, {2, 8, 2, 9}, {9, 1, 9, 2}, {7, 3, 7, 2}, {3, 7, 3, 8}, {1, 9, 1, 8}, {9, 1, 9, 4}, {7, 3, 7, 6}, {3, 7, 3, 4}, {1, 9, 1, 6}, // points
1626 // points always have links 0 & 2 = lead, link 1 = trailing straight (or left diverging if no straight), link 3 = trailing diverging
1627 // (or right diverging if no straight)
1628  {1, 9, 2, 8}, {2, 8, 3, 7}, {4, 6, 3, 7}, {1, 9, 4, 6}, // crossover links 0 & 1 = diagonal top left to Bottom right, then horizontal, then vertical
1629  {2, 8, 4, 6}, {4, 6, 2, 8}, {3, 7, 1, 9}, {1, 9, 3, 7}, {2, 8, 1, 9}, {2, 8, 3, 7}, {3, 7, 2, 8}, {1, 9, 2, 8}, {4, 6, 3, 7}, {4, 6, 1, 9}, {1, 9, 4, 6}, {3, 7, 4, 6}, // bridge, links 2 & 3 = underbridge
1630  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // buffers - position 0 = buffer
1631  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, // signals (need Config to determine signal end, see below)
1632  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // platform
1633  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // continuation - position 0 = continuation
1634  {4, 6, -1, -1}, {6, 4, -1, -1}, {8, 2, -1, -1}, {2, 8, -1, -1}, {1, 9, -1, -1}, {3, 7, -1, -1}, {7, 3, -1, -1}, {9, 1, -1, -1}, // gapjump - position 0 = gap
1635  {-1, -1, -1, -1}, // Concourse
1636  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1637  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1638  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1},
1639  {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, {-1, -1, -1, -1}, // Parapets
1640  {4, 6, -1, -1}, {4, 6, -1, -1}, {2, 8, -1, -1}, {2, 8, -1, -1}, // arrows
1641  {4, 6, -1, -1}, {2, 8, -1, -1}, // footbridges
1642  {-1, -1, -1, -1}, // NamedNonStationLocation
1643  {8, 1, 8, 3}, {4, 3, 4, 9}, {2, 9, 2, 7}, {6, 7, 6, 1}, {9, 4, 9, 2}, {7, 2, 7, 6}, {1, 6, 1, 8}, {3, 8, 3, 4}, // points without straight legs
1644 // these points have links 0 & 2 = lead, link 1 = LH trailing, link 3 = RH trailing
1645  {3, 7, -1, -1}, {3, 7, -1, -1}, {1, 9, -1, -1}, {1, 9, -1, -1}, // arrowed diagonals
1646  {-1, -1, -1, -1}, // level crossing
1647  {4, 6, -1, -1}, {2, 8, -1, -1}, // underpasses/surface crossings
1648  };
1649 
1651  {{NotSet, NotSet, NotSet, NotSet}, // unused
1655  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1657  {NotSet, NotSet, NotSet, NotSet}, // unused
1661  {Connection, Connection, NotSet, NotSet}, // simple
1665  {Lead, Trail, Lead, Trail}, // points
1667  {CrossConn, CrossConn, CrossConn, CrossConn}, // crossover
1675  {Signal, Connection, NotSet, NotSet}, {Signal, Connection, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, {Connection, Signal, NotSet, NotSet}, // signals (signal at exit end in forward direction)
1681  {NotSet, NotSet, NotSet, NotSet}, // Concourse
1690  {Connection, Connection, NotSet, NotSet}, // Arrows
1692  {NotSet, NotSet, NotSet, NotSet}, // NamedNonStationLocation
1694  {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, {Lead, Trail, Lead, Trail}, // points
1696  {Connection, Connection, NotSet, NotSet}, // Arrowed diagonals
1697  {NotSet, NotSet, NotSet, NotSet}, // Level crossing
1698  {Connection, Connection, NotSet, NotSet}, {Connection, Connection, NotSet, NotSet} // Underpasses/surface crossings
1699  };
1700 
1701  for(int x = 0; x < 17; x++)
1702  {
1703  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1704  }
1705  FixedTrackPiece[17] = TFixedTrackPiece(17, TrackTypeArray[17], Links[17], Configs[17], 0, 0);
1706 // 17 was the old text value so don't want any graphics (now disused)
1707  for(int x = 18; x < FirstUnusedSpeedTagNumber; x++)
1708  {
1709  FixedTrackPiece[x] = TFixedTrackPiece(x, TrackTypeArray[x], Links[x], Configs[x], TrackImageArray[x], SmallTrackImageArray[x]);
1710  }
1711 }
1712 
1713 // ---------------------------------------------------------------------------
1714 TGraphicElement::TGraphicElement() : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1715  ExistingGraphicLoaded(false), Width(16), Height(16)
1716 {
1717  OriginalGraphic = new Graphics::TBitmap;
1718  OriginalGraphic->PixelFormat = pf8bit;
1719  OriginalGraphic->Width = Width;
1720  OriginalGraphic->Height = Height;
1721  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1722 }
1723 
1724 // ---------------------------------------------------------------------------
1725 
1726 TGraphicElement::TGraphicElement(int WidthIn, int HeightIn) : OverlayPlotted(false), OriginalLoaded(false), ScreenSourceSet(false), ScreenGraphicLoaded(false),
1727  ExistingGraphicLoaded(false), Width(WidthIn), Height(HeightIn)
1728 {
1729  OriginalGraphic = new Graphics::TBitmap;
1730  OriginalGraphic->PixelFormat = pf8bit;
1731  OriginalGraphic->Width = Width;
1732  OriginalGraphic->Height = Height;
1733  OriginalGraphic->Transparent = false; // seems to default to false but set it to be sure, so no need to plot a blank before each replot
1734 }
1735 
1736 // ---------------------------------------------------------------------------
1737 
1739 {
1740  delete OriginalGraphic;
1741 }
1742 
1743 // ---------------------------------------------------------------------------
1744 
1745 void TGraphicElement::SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
1746 {
1747  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetScreenHVSource," + AnsiString(HPosIn) + "," + AnsiString(VPosIn));
1748  HPos = HPosIn; // HPos & VPos are members of TGraphicElement
1749  VPos = VPosIn;
1750  int Left, Top; // can't use e.g. PointFlash.SourceRect.Left & Top directly as references as don't exist as objects in their own right
1751 
1752  Track->GetScreenPositionsFromTruePos(2, Left, Top, HPos, VPos);
1753  SourceRect.init(Left, Top, Left + Width, Top + Height);
1754  ScreenSourceSet = true;
1755  Utilities->CallLogPop(422);
1756 }
1757 
1758 // ---------------------------------------------------------------------------
1759 
1761 {
1762  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalScreenGraphic");
1763  if(!OverlayLoaded)
1764  {
1765  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalScreenGraphic()");
1766  }
1767  if((OverlayGraphic->Width != 16) || (OverlayGraphic->Height != 16))
1768  {
1769  throw Exception("Overlay not 16x16 in TGraphicElement::LoadOriginalScreenGraphic()");
1770  }
1771  if(!ScreenSourceSet)
1772  {
1773  throw Exception("Source not set in TGraphicElement::LoadOriginalScreenGraphic()");
1774  }
1775  if(ExistingGraphicLoaded) // can only call one of the load functions
1776  {
1777  throw Exception("ExistingGraphicLoaded in TGraphicElement::LoadOriginalScreenGraphic()");
1778  }
1779  if(OverlayPlotted) // don't load from screen if overlay plotted
1780  {
1781  Utilities->CallLogPop(775);
1782  return;
1783  }
1784  TRect DestRect(0, 0, Width, Height);
1785 
1787  OriginalLoaded = true;
1788  ScreenGraphicLoaded = true;
1789  Utilities->CallLogPop(423);
1790 }
1791 
1792 // ---------------------------------------------------------------------------
1793 
1794 void TGraphicElement::LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
1795 /*
1796  Overrides size set in the constructor, SourceRect & HPos & VPos in SetScreenHVSource
1797 */
1798 {
1799  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOriginalExistingGraphic," + AnsiString(HOffset) + "," +
1800  AnsiString(VOffset) + "," + AnsiString(WidthIn) + "," + AnsiString(HeightIn));
1801  if(!OverlayLoaded)
1802  {
1803  throw Exception("Overlay not loaded in TGraphicElement::LoadOriginalExistingGraphic()");
1804  }
1805  if(!ScreenSourceSet) // has to be called to set HPos & VPos
1806  {
1807  throw Exception("Source not set in TGraphicElement::LoadOriginalExistingGraphic()");
1808  }
1809  if(ScreenGraphicLoaded) // can only call one of the load functions
1810  {
1811  throw Exception("ScreenGraphicLoaded in TGraphicElement::LoadOriginalExistingGraphic()");
1812  }
1813  Width = WidthIn;
1814  Height = HeightIn;
1815  OriginalGraphic->Width = Width;
1816  OriginalGraphic->Height = Height;
1817  HPos += HOffset; // originally set in SetScreenHVSource to position of H & V locations
1818  VPos += VOffset;
1819  TRect DestRect(0, 0, Width, Height);
1820 
1821  SourceRect.init(HOffset, VOffset, HOffset + Width, VOffset + Height);
1822  OriginalGraphic->Canvas->CopyRect(DestRect, Graphic->Canvas, SourceRect);
1823  OriginalLoaded = true;
1824  ExistingGraphicLoaded = true;
1825  Utilities->CallLogPop(424);
1826 }
1827 
1828 // ---------------------------------------------------------------------------
1829 
1830 void TGraphicElement::LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
1831 {
1832  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOverlayGraphic,");
1833  OverlayGraphic = Overlay;
1834  OverlayLoaded = true;
1835  Utilities->CallLogPop(425);
1836 }
1837 
1838 // ---------------------------------------------------------------------------
1839 
1841 {
1842  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOverlay,");
1843  if(!OverlayLoaded)
1844  {
1845  throw Exception("Overlay not loaded in TGraphicElement::PlotOverlay()");
1846  }
1847  if(!OverlayPlotted)
1848  {
1849  Disp->PlotOutput(35, HPos, VPos, OverlayGraphic); // plot overlay
1850  Disp->Update();
1851  OverlayPlotted = true;
1852  }
1853  Utilities->CallLogPop(426);
1854 }
1855 
1856 // ---------------------------------------------------------------------------
1857 
1859 {
1860  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotOriginal,");
1861  if(OverlayPlotted)
1862  {
1863  if(!OriginalLoaded) // this comes after OverlayPlotted because may wish to 'try' to plot original even
1864  // when it isn't loaded in case it had been plotted - e.g. when change user modes
1865  {
1866  throw Exception("Original not loaded in TGraphicElement::PlotOriginal()");
1867  }
1868  Disp->PlotOutput(36, HPos, VPos, OriginalGraphic); // replot original
1869  Disp->Update(); // This was commented out originally but when in flashes much less frequent when points changing manually
1870  OverlayPlotted = false;
1871  }
1872  Utilities->CallLogPop(427);
1873 }
1874 
1875 // ---------------------------------------------------------------------------
1876 
1878 {
1879  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoTrack");
1880  bool TrackPresent = false;
1881 
1882  if(InactiveTrackVector.size() != 0)
1883  {
1884  Utilities->CallLogPop(1333);
1885  return(false);
1886  }
1887  else if(TrackVector.size() == 0)
1888  {
1889  Utilities->CallLogPop(1334);
1890  return(true);
1891  }
1892  else
1893  {
1894  for(unsigned int x = 0; x < TrackVector.size(); x++)
1895  {
1896  if((TrackElementAt(1042, x).SpeedTag != 0))
1897  {
1898  TrackPresent = true;
1899  }
1900  }
1901  }
1902  Utilities->CallLogPop(1335);
1903  return(!TrackPresent);
1904 }
1905 
1906 // ---------------------------------------------------------------------------
1907 
1908 bool TTrack::NoActiveTrack(int Caller)
1909 {
1910  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoActiveTrack");
1911  bool TrackPresent = false;
1912 
1913  if(TrackVector.size() == 0)
1914  {
1915  Utilities->CallLogPop(1582);
1916  return(true);
1917  }
1918  else
1919  {
1920  for(unsigned int x = 0; x < TrackVector.size(); x++)
1921  {
1922  if((TrackElementAt(1043, x).SpeedTag != 0))
1923  {
1924  TrackPresent = true;
1925  }
1926  break;
1927  }
1928  }
1929  Utilities->CallLogPop(1583);
1930  return(!TrackPresent);
1931 }
1932 
1933 // ---------------------------------------------------------------------------
1934 
1935 void TTrack::EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
1936 {
1937  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseTrackElement," + AnsiString(HLocInput) + "," +
1938  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
1939  TrackEraseSuccessfulFlag = false;
1940 // TrackEraseSuccessfulFlag used for both track element and inactive element erase,
1941 // since have to match platforms as well as track
1942 // used to set TrackFinished to false if an element erased
1943 
1944  ErasedTrackVectorPosition = -1; // marker for no element erased
1945  AnsiString SName = "", ErrorString;
1947  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
1948  TTrackMapIterator TrackMapPtr;
1949  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
1950 
1951  if(TrackVector.size() != 0)
1952  {
1953  TrackMapKeyPair.first = HLocInput;
1954  TrackMapKeyPair.second = VLocInput;
1955  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
1956  if(TrackMapPtr != TrackMap.end())
1957  {
1958  bool FoundFlag;
1959  int VecPos = GetVectorPositionFromTrackMap(37, HLocInput, VLocInput, FoundFlag);
1960  if(FoundFlag) // should find it as it's in the map
1961  {
1962  if(TrackElementAt(629, VecPos).FixedNamedLocationElement) // footcrossings only
1963  {
1964  SName = TrackElementAt(1, VecPos).LocationName;
1965  SNIt = FindNamedElementInLocationNameMultiMap(7, SName, TrackVector.begin() + VecPos, ErrorString);
1966  if(ErrorString != "")
1967  {
1968  throw Exception(ErrorString + " for EraseTrackElement 1");
1969  }
1970  LocationNameMultiMap.erase(SNIt);
1971  }
1972  TrackVector.erase(TrackVector.begin() + TrackMapPtr->second);
1973  // ensure erase vector element before map element as iterator no longer valid after a map erase
1974  TrackMap.erase(TrackMapPtr);
1975  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(2, HLocInput, VLocInput); // plot a blank element
1976  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
1978  ResetAnyNonMatchingGaps(1); // in case the deleted element was a set gap
1979  if(SName != "")
1980  {
1981  EraseLocationAndActiveTrackElementNames(5, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
1982  int HPos, VPos;
1983  if(TextHandler->FindText(1, SName, HPos, VPos))
1984  {
1985  if(TextHandler->TextErase(5, HPos, VPos, SName))
1986  {
1987  ;
1988  } // condition not used
1989 
1990  }
1991  }
1992  ErasedTrackVectorPosition = VecPos;
1993  TrackEraseSuccessfulFlag = true;
1994  }
1995  }
1996  }
1997  if(InactiveTrackVector.size() != 0)
1998  {
1999  unsigned int VecPos;
2000  InactiveTrackMapKeyPair.first = HLocInput;
2001  InactiveTrackMapKeyPair.second = VLocInput;
2002  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair);
2003  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2004  {
2005  SName = "";
2006  VecPos = InactiveTrack2MultiMapIterator->second;
2007  if(InactiveTrackElementAt(0, VecPos).FixedNamedLocationElement)
2008  {
2009  SName = InactiveTrackElementAt(1, VecPos).LocationName;
2010  SNIt = FindNamedElementInLocationNameMultiMap(2, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2011  if(ErrorString != "")
2012  {
2013  throw Exception(ErrorString + " for EraseTrackElement 2A");
2014  }
2015  LocationNameMultiMap.erase(SNIt);
2016  }
2017  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2018  // ensure erase vector element before map element as iterator no longer valid after a map erase
2019  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2020  FixedTrackArray.FixedTrackPiece[0].PlotFixedTrackElement(1, HLocInput, VLocInput); // plot a blank element
2021  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2023  TrackEraseSuccessfulFlag = true;
2024  if(SName != "")
2025  {
2026  EraseLocationAndActiveTrackElementNames(3, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2027  int HPos, VPos;
2028  if(TextHandler->FindText(2, SName, HPos, VPos))
2029  {
2030  if(TextHandler->TextErase(6, HPos, VPos, SName))
2031  {
2032  ;
2033  } // condition not used
2034 
2035  }
2036  }
2037  }
2038  if(InactiveTrackVector.size() != 0) // need to check again as last access may have erased the last element
2039  {
2040  InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // may be up to 2 elements (platforms) at same location
2041  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
2042  {
2043  SName = "";
2044  VecPos = InactiveTrack2MultiMapIterator->second;
2045  if(InactiveTrackElementAt(2, VecPos).FixedNamedLocationElement)
2046  {
2047  SName = InactiveTrackElementAt(3, VecPos).LocationName;
2048  SNIt = FindNamedElementInLocationNameMultiMap(3, SName, InactiveTrackVector.begin() + VecPos, ErrorString);
2049  if(ErrorString != "")
2050  {
2051  throw Exception(ErrorString + " for EraseTrackElement 2B");
2052  }
2053  LocationNameMultiMap.erase(SNIt);
2054  }
2055  InactiveTrackVector.erase(InactiveTrackVector.begin() + InactiveTrack2MultiMapIterator->second); // if inactive can erase immediately
2056  InactiveTrack2MultiMap.erase(InactiveTrack2MultiMapIterator);
2057  // need to decrement all map element position values that lie above VecPos, since vector positions above this have all moved down one
2059  if(SName != "")
2060  {
2061  EraseLocationAndActiveTrackElementNames(4, SName); // this instead of SearchForAndUpdateLocationName later (saves time)
2062  int HPos, VPos;
2063  if(TextHandler->FindText(3, SName, HPos, VPos))
2064  {
2065  if(TextHandler->TextErase(7, HPos, VPos, SName))
2066  {
2067  ;
2068  } // condition not used
2069 
2070  }
2071  }
2072  }
2073  }
2074  }
2075  if(TrackEraseSuccessfulFlag)
2076  {
2077  CalcHLocMinEtc(2);
2078  SetTrackFinished(false);
2079  }
2080  if(InternalChecks)
2081  {
2082  CheckMapAndTrack(1); // test
2083  CheckMapAndInactiveTrack(1); // test
2084  CheckLocationNameMultiMap(6); // test
2085  }
2086  Utilities->CallLogPop(428);
2087 }
2088 
2089 // ---------------------------------------------------------------------------
2090 
2091 void TTrack::PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
2092 // TrackLinkingRequiredFlag only relates to elements that require track linking after plotting - used to set TrackFinished
2093 // to false in calling function. New at v2.2.0 new parameter 'Aspect' to ensure signals plotted with correct number of aspects (for pasting)
2094 // and also when zero and combined with SignalPost to indicate that adding track rather than pasting
2095 {
2096  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotAndAddTrackElement," + AnsiString(CurrentTag) + "," +
2097  AnsiString(HLocInput) + "," + AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2098  bool PlatAllowedFlag = false;
2099 
2100  TrackLinkingRequiredFlag = false;
2101 /*
2102  Not erase, that covered separately.
2103  First check if Current SpeedButton assigned, then check if a platform and only
2104  permit if an appropriate trackpiece already there & not a same platform there.
2105  - can't enter a platform without track first.
2106  Then for non-platforms, check if a track piece already present at location &
2107  reject if so.
2108 */
2109 
2110  TLocationNameMultiMapEntry LocationNameEntry;
2111 
2112  LocationNameEntry.first = "";
2113  if(CurrentTag == 0)
2114  {
2115  Utilities->CallLogPop(429);
2116  return; // not assigned yet
2117  }
2118  TTrackElement TempTrackElement(FixedTrackArray.FixedTrackPiece[CurrentTag]);
2119 
2120  TempTrackElement.HLoc = HLocInput;
2121  TempTrackElement.VLoc = VLocInput;
2122  SetElementID(1, TempTrackElement); // TempTrackElement is the one to be added
2123 // new at version 0.6 - set signal aspect depending on build mode
2124 
2125  if(TempTrackElement.TrackType == SignalPost)
2126  {
2127  if(Aspect == 0) // new at v2.2.0, '0' and SignalPost together means that track being added & not pasted, because when
2128  // pasting a SignalPost can only have values 1 to 4
2129  {
2131  {
2132  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2133  }
2135  {
2136  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2137  }
2139  {
2140  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2141  }
2142  else
2143  {
2144  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2145  }
2146  }
2147  else if(Aspect == 1)
2148  {
2149  TempTrackElement.SigAspect = TTrackElement::GroundSignal;
2150  }
2151  else if(Aspect == 2)
2152  {
2153  TempTrackElement.SigAspect = TTrackElement::TwoAspect;
2154  }
2155  else if(Aspect == 3)
2156  {
2157  TempTrackElement.SigAspect = TTrackElement::ThreeAspect;
2158  }
2159  else
2160  {
2161  TempTrackElement.SigAspect = TTrackElement::FourAspect;
2162  }
2163  }
2164  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2165  int VecPos = GetVectorPositionFromTrackMap(12, HLocInput, VLocInput, FoundFlag); // active track already there
2166  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(5, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2167  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2168 
2169  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2170  {
2172  {
2173  NonStationOrLevelCrossingPresent = true;
2174  }
2175  if(InactiveTrackElementAt(117, IMPair.first).TrackType == LevelCrossing)
2176  {
2177  NonStationOrLevelCrossingPresent = true;
2178  }
2179  if(InactiveTrackElementAt(5, IMPair.first).TrackType == Platform)
2180  {
2181  PlatformPresent = true;
2182  }
2183  // no need to check IMPair.second since if that exists it is because .first is a platform
2184  InactiveSpeedTag1 = InactiveTrackElementAt(6, IMPair.first).SpeedTag;
2185  InactiveSpeedTag2 = InactiveTrackElementAt(7, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2186  }
2187 // check platforms
2188  if(TempTrackElement.TrackType == Platform)
2189  {
2190  if(FoundFlag) // active track element already there
2191  {
2192  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2193  {
2194  ;
2195  }
2196  // same platform type already there so above keeps PlatAllowedFlag false
2197  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1044, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2198  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2199  {
2200  PlatAllowedFlag = true;
2201  }
2202  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1045, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2203  {
2204  PlatAllowedFlag = true;
2205  }
2206  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1046, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2207  {
2208  PlatAllowedFlag = true;
2209  }
2210  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1047, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2211  {
2212  PlatAllowedFlag = true;
2213  }
2214  if(PlatAllowedFlag)
2215  {
2216  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2217  TrackPush(1, TempTrackElement);
2218  SearchForAndUpdateLocationName(1, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2219  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2220  // Must be called AFTER TrackPush
2221  // No need to plot the element - Clearand ... called after this function called
2222  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2223  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2224 // drop in v2.4.0 if(TrackElementAt(2, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2225 // AnsiString(TrackElementAt(3, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2226 // TrackElementAt(4, VecPos).Length01 = DefaultTrackLength;
2227  if(InternalChecks)
2228  {
2229  CheckMapAndInactiveTrack(5); // test
2230  CheckLocationNameMultiMap(4); // test
2231  }
2232  Utilities->CallLogPop(430);
2233  return;
2234  }
2235  } // if(FoundFlag)
2236 
2237  Utilities->CallLogPop(431);
2238  return;
2239  } // if platform
2240 
2241 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2242  if(TempTrackElement.TrackType == NamedNonStationLocation)
2243  {
2244  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1048, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2245  (!FoundFlag && !InactiveFoundFlag))
2246  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2247  {
2248  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2249  TrackPush(2, TempTrackElement);
2250  SearchForAndUpdateLocationName(2, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2251  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2252  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2253  {
2254 // drop in v2.4.0 if(TrackElementAt(830, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2255 // AnsiString(TrackElementAt(831, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2256 // TrackElementAt(832, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2257  }
2258  if(InternalChecks)
2259  {
2260  CheckMapAndInactiveTrack(11); // test
2261  CheckLocationNameMultiMap(12); // test
2262  }
2263  Utilities->CallLogPop(432);
2264  return;
2265  }
2266  else
2267  {
2268  Utilities->CallLogPop(433);
2269  return;
2270  }
2271  }
2272 // check if a level crossing - OK if placed on a plain straight track
2273  if(TempTrackElement.TrackType == LevelCrossing)
2274  {
2275  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1049, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2276  {
2277  TrackPush(11, TempTrackElement);
2278  PlotRaisedLinkedLevelCrossingBarriers(0, TrackElementAt(1050, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2279 // no need for reference to LC element as can't be open
2280  TrackLinkingRequiredFlag = true;
2281  Utilities->CallLogPop(1907);
2282  return;
2283  }
2284  else
2285  {
2286  Utilities->CallLogPop(1906);
2287  return; // was a level crossing but can't place it for some reason
2288  }
2289  }
2290 
2291 // check if another element already there
2292  else if(FoundFlag || InactiveFoundFlag)
2293  {
2294  Utilities->CallLogPop(434);
2295  return; // something already there (active or inactive track)
2296  }
2297 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2298 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2299 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2300 // do this after pushed into vector so that can use EnterLocationName
2301 
2302  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2303  {
2304  TrackPush(3, TempTrackElement);
2305  SearchForAndUpdateLocationName(3, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2306  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2307  }
2308  else if(TempTrackElement.TrackType == Points)
2309  {
2310  TrackPush(4, TempTrackElement);
2311  bool BothPointFillets = true;
2312  PlotPoints(6, TempTrackElement, Display, BothPointFillets);
2313  }
2314  else if(TempTrackElement.TrackType == SignalPost)
2315  {
2316  TrackPush(10, TempTrackElement);
2317  PlotSignal(12, TempTrackElement, Display);
2318  }
2319  else
2320  {
2321  TrackPush(5, TempTrackElement);
2322  TempTrackElement.PlotVariableTrackElement(1, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2323  }
2324  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2325  {
2326  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2327  }
2328  if(InternalChecks)
2329  {
2330  CheckMapAndTrack(2); // test
2331  CheckMapAndInactiveTrack(2); // test
2332  CheckLocationNameMultiMap(5); // test
2333  }
2334  Utilities->CallLogPop(2062);
2335 }
2336 
2337 // ---------------------------------------------------------------------------
2338 
2339 void TTrack::PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag,
2340  bool InternalChecks)
2341 // new at v2.2.0 - similar to above but keeping speed & length attributes (for pasting) and also pastes location names
2342 {
2343  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPastedTrackElementWithAttributes," + AnsiString(HLocInput) + "," +
2344  AnsiString(VLocInput) + "," + AnsiString((short)InternalChecks));
2345  bool PlatAllowedFlag = false;
2346 
2347  TrackLinkingRequiredFlag = false;
2348  TLocationNameMultiMapEntry LocationNameEntry;
2349 
2350  LocationNameEntry.first = "";
2351  if(TempTrackElement.SpeedTag == 0)
2352  {
2353  Utilities->CallLogPop(2063);
2354  return; // not assigned yet
2355  }
2356  TempTrackElement.HLoc = HLocInput;
2357  TempTrackElement.VLoc = VLocInput;
2358  for(int x = 0; x < 4; x++) // unset any gaps
2359  {
2360  if(TempTrackElement.Config[x] == Gap)
2361  {
2362  TempTrackElement.ConnLinkPos[x] = -1;
2363  }
2364  TempTrackElement.Conn[x] = -1;
2365  }
2366  SetElementID(5, TempTrackElement); // TempTrackElement is the one to be added
2367 // new at version 0.6 - set signal aspect depending on build mode
2368  bool FoundFlag = false, InactiveFoundFlag = false, NonStationOrLevelCrossingPresent = false, PlatformPresent = false;
2369  int VecPos = GetVectorPositionFromTrackMap(56, HLocInput, VLocInput, FoundFlag); // active track already there
2370 
2371  // if find an active track element (as has been pasted into track vector when dealing with inactive elements in SelectVector)
2372  // )set its ActiveTrackElementName to same name as the inactive element (from SelectVector). Note that can't use LocationName
2373  // for the active track element because these aren't set
2374  // if don't do this then get a mismatch error during map checks later
2375 
2376  // if(FoundFlag) TrackElementAt(xx, VecPos).ActiveTrackElementName = TempTrackElement.LocationName; //doesn't work!!
2377 
2378  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(26, HLocInput, VLocInput, InactiveFoundFlag); // inactive track already there
2379  int InactiveSpeedTag1 = 0, InactiveSpeedTag2 = 0;
2380 
2381  if(InactiveFoundFlag) // check if a LocationName already there & if so disallow platform
2382  {
2383  if(InactiveTrackElementAt(119, IMPair.first).TrackType == NamedNonStationLocation)
2384  {
2385  NonStationOrLevelCrossingPresent = true;
2386  }
2387  if(InactiveTrackElementAt(120, IMPair.first).TrackType == LevelCrossing)
2388  {
2389  NonStationOrLevelCrossingPresent = true;
2390  }
2391  if(InactiveTrackElementAt(121, IMPair.first).TrackType == Platform)
2392  {
2393  PlatformPresent = true;
2394  }
2395  // no need to check IMPair.second since if that exists it is because .first is a platform
2396  InactiveSpeedTag1 = InactiveTrackElementAt(122, IMPair.first).SpeedTag;
2397  InactiveSpeedTag2 = InactiveTrackElementAt(123, IMPair.second).SpeedTag; // note .first & .second will be same if only one present
2398  }
2399 // check platforms
2400  if(TempTrackElement.TrackType == Platform)
2401  {
2402  if(FoundFlag) // active track element already there
2403  {
2404  if(InactiveFoundFlag && ((TempTrackElement.SpeedTag == InactiveSpeedTag1) || (TempTrackElement.SpeedTag == InactiveSpeedTag2)))
2405  {
2406  ;
2407  }
2408  // same platform type already there so above keeps PlatAllowedFlag false
2409  else if((TempTrackElement.SpeedTag == 76) && (TopPlatAllowed.Contains(TrackElementAt(1051, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2410  // won't allow a same platform, as TopPlatAllowed not valid for a same platform <--NO, only checks active track, same plat disallowed by first line after if(FoundFlag)
2411  {
2412  PlatAllowedFlag = true;
2413  }
2414  else if((TempTrackElement.SpeedTag == 77) && (BotPlatAllowed.Contains(TrackElementAt(1052, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2415  {
2416  PlatAllowedFlag = true;
2417  }
2418  else if((TempTrackElement.SpeedTag == 78) && (LeftPlatAllowed.Contains(TrackElementAt(1053, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2419  {
2420  PlatAllowedFlag = true;
2421  }
2422  else if((TempTrackElement.SpeedTag == 79) && (RightPlatAllowed.Contains(TrackElementAt(1054, VecPos).SpeedTag)) && !NonStationOrLevelCrossingPresent)
2423  {
2424  PlatAllowedFlag = true;
2425  }
2426  if(PlatAllowedFlag)
2427  {
2428  TrackLinkingRequiredFlag = true; // needed in order to call LinkTrack
2429  TrackPush(12, TempTrackElement);
2430 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2431  {
2432  SearchForAndUpdateLocationName(4, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2433  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2434  }
2435  // Must be called AFTER TrackPush
2436 // No need to plot the element - Clearand ... called after this function called
2437  // set corresponding track element length to 100m & give message if was different drop in v2.4.0
2438  // note can only be Length01 since even if points then only the straight part can be adjacent to the platform
2439 // drop in v2.4.0 if(TrackElementAt(907, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2440 // AnsiString(TrackElementAt(908, VecPos).Length01) + "m. It will be reset to 100m since all platform track lengths are fixed at 100m");
2441 // TrackElementAt(909, VecPos).Length01 = DefaultTrackLength;
2442  if(InternalChecks)
2443  {
2444  CheckMapAndInactiveTrack(12); // test
2445  CheckLocationNameMultiMap(20); // test
2446  }
2447  Utilities->CallLogPop(2064);
2448  return;
2449  }
2450  } // if(FoundFlag)
2451 
2452  Utilities->CallLogPop(2065);
2453  return;
2454  } // if platform
2455 
2456 // check if element is a LocationName - OK if placed on an allowable track element, or on a blank element
2457  if(TempTrackElement.TrackType == NamedNonStationLocation)
2458  {
2459  if((FoundFlag && (NameAllowed.Contains(TrackElementAt(1055, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag) ||
2460  (!FoundFlag && !InactiveFoundFlag))
2461  // need to add && !NonStationOrLevelCrossingPresent, or better - !InactiveFoundFlag to above FoundFlag condition <-- OK done
2462  {
2463  TrackLinkingRequiredFlag = true; // needed in case have named a continuation, need to check if adjacent element named
2464  TrackPush(13, TempTrackElement);
2465 // if(!CopyFlag) // don't need this for copy - yes we do, this is so a location will be named if pasted next to a named location - condition removed at v2.6.0
2466  {
2467  SearchForAndUpdateLocationName(5, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2468  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2469  }
2470  if(VecPos > -1) // need to allow for non-station named locations that aren't on tracks
2471  {
2472 // drop in v2.4.0 if(TrackElementAt(910, VecPos).Length01 != DefaultTrackLength) ShowMessage("Note: The track element at this location has a length of " +
2473 // AnsiString(TrackElementAt(911, VecPos).Length01) + "m. It will be reset to 100m since all named location track lengths are fixed at 100m");
2474 // TrackElementAt(912, VecPos).Length01 = DefaultTrackLength; //NB named locations can only be placed at one track elements
2475  }
2476  if(InternalChecks)
2477  {
2478  CheckMapAndInactiveTrack(13); // test
2479  CheckLocationNameMultiMap(21); // test
2480  }
2481  Utilities->CallLogPop(2066);
2482  return;
2483  }
2484  else
2485  {
2486  Utilities->CallLogPop(2067);
2487  return;
2488  }
2489  }
2490 // check if a level crossing - OK if placed on a plain straight track
2491  if(TempTrackElement.TrackType == LevelCrossing)
2492  {
2493  if(FoundFlag && (LevelCrossingAllowed.Contains(TrackElementAt(1056, VecPos).SpeedTag)) && !PlatformPresent && !InactiveFoundFlag)
2494  {
2495  TrackPush(14, TempTrackElement);
2496  PlotRaisedLinkedLevelCrossingBarriers(3, TrackElementAt(1057, VecPos).SpeedTag, TempTrackElement.HLoc, TempTrackElement.VLoc, Display); //always plots red
2497 // no need for reference to LC element as can't be open
2498  TrackLinkingRequiredFlag = true;
2499  Utilities->CallLogPop(2068);
2500  return;
2501  }
2502  else
2503  {
2504  Utilities->CallLogPop(2069);
2505  return; // was a level crossing but can't place it for some reason
2506  }
2507  }
2508 
2509 // check if another element already there
2510  else if(FoundFlag || InactiveFoundFlag)
2511  {
2512  Utilities->CallLogPop(2070);
2513  return; // something already there (active or inactive track)
2514  }
2515 // add LocationName if a FixedNamedLocationElement by checking for any adjacent names, then give all linked named location
2516 // elements the same name - in case had linked 2 separately named locations - all get the one name that it finds
2517 // first from an adjacent element search, also non-named location elements at platform locations have timetable name set
2518 // do this after pushed into vector so that can use EnterLocationName
2519 
2520  if(TempTrackElement.FixedNamedLocationElement) // concourse or footcrossing (platforms & named non-station locations already dealt with)
2521  {
2522  TrackPush(15, TempTrackElement);
2523  SearchForAndUpdateLocationName(6, TempTrackElement.HLoc, TempTrackElement.VLoc, TempTrackElement.SpeedTag);
2524  // checks all adjacent locations and if any name found that one is used for all elements that are now linked to it
2525  }
2526  else if(TempTrackElement.TrackType == Points)
2527  {
2528  TrackPush(16, TempTrackElement);
2529  bool BothPointFillets = true;
2530  PlotPoints(7, TempTrackElement, Display, BothPointFillets);
2531  }
2532  else if(TempTrackElement.TrackType == SignalPost)
2533  {
2534  TrackPush(17, TempTrackElement);
2535  PlotSignal(14, TempTrackElement, Display);
2536  }
2537  else
2538  {
2539  TrackPush(18, TempTrackElement);
2540  TempTrackElement.PlotVariableTrackElement(6, Display); // all named locations already dealt with so no ambiguity between striped & non-striped
2541  }
2542  if((TempTrackElement.TrackType != Concourse) && (TempTrackElement.TrackType != Parapet))
2543  {
2544  TrackLinkingRequiredFlag = true; // plats & NamedLocs aleady dealt with
2545  }
2546  if(InternalChecks)
2547  {
2548  CheckMapAndTrack(12); // test
2549  CheckMapAndInactiveTrack(14); // test
2550  CheckLocationNameMultiMap(22); // test
2551  }
2552  Utilities->CallLogPop(2071);
2553 }
2554 
2555 // ---------------------------------------------------------------------------
2556 
2557 bool TTrack::TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
2558 // GiveMessages relates to the call to LinkTrack or LinkTrackNoMessages
2559 // return bool = true for success
2560 // LocError = true for location error & HLoc & VLoc to be inverted
2561 {
2562  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TryToConnectTrack," + AnsiString((short)GiveMessages));
2563  LocError = false;
2564  SetTrackFinished(false);
2565  if(TrackVector.size() == 0)
2566  {
2567  Utilities->CallLogPop(437);
2568  return(false);
2569  }
2570  if(GapsUnset(7))
2571  {
2572  if(GiveMessages)
2573  {
2574  ShowMessage("Gaps must be set before track can be validated");
2575  }
2576  Utilities->CallLogPop(1135);
2577  return(false);
2578  }
2579 // below sets all Conns and CLks to -1 except for gapjumps that match and are properly set,
2580 // returns true for any unset gaps
2582  {
2583  // can keep this exception as protected by the GapsUnset call above
2584  throw Exception("Error, gaps unset when TryToConnectTrack called");
2585  }
2587  CheckGapMap(1); // test
2588 // Gap connections now securely defined
2589 
2590  CheckMapAndTrack(8); // test
2591 
2592 // Perform a pre-check prior to TrackMap being compiled
2593  if(GiveMessages)
2594  {
2595  if(!LinkTrack(1, LocError, HLoc, VLoc, false))
2596  {
2597  Utilities->CallLogPop(439);
2598  return(false);
2599  }
2600  }
2601  else
2602  {
2603  if(!LinkTrackNoMessages(1, false))
2604  {
2605  Utilities->CallLogPop(1131);
2606  return(false);
2607  }
2608  }
2609 // here if pre-check successful
2610  if(!RepositionAndMapTrack(0))
2611  {
2612  ShowMessage("Error in RepositionAndMapTrack during TryToConnectTrack. Railway file is corrupt, further use may cause a system crash");
2613  Utilities->CallLogPop(1138);
2614  return(false);
2615  }
2616 // now perform the final assembly - FinalCall = true
2617  if(GiveMessages)
2618  {
2619  if(!LinkTrack(2, LocError, HLoc, VLoc, true))
2620  {
2621  Utilities->CallLogPop(1116);
2622  return(false);
2623  }
2624  }
2625  else
2626  {
2627  if(!LinkTrackNoMessages(2, true))
2628  {
2629  Utilities->CallLogPop(1132);
2630  return(false);
2631  }
2632  }
2633 // success
2634 
2635  PopulateLCVector(0);
2636  CheckGapMap(2); // test
2637  CheckMapAndTrack(3); // test
2638  CheckMapAndInactiveTrack(3); // test
2639  CheckLocationNameMultiMap(9); // test
2640  SetTrackFinished(true);
2641 
2642 // Build ContinuationNameMap
2643  std::pair<AnsiString, char>TempMapPair;
2644 
2645  ContinuationNameMap.clear();
2646  for(int x = 0; x < Track->TrackVectorSize(); x++)
2647  {
2648  if((Track->TrackElementAt(1058, x).TrackType == Continuation) && (Track->TrackElementAt(1059, x).ActiveTrackElementName != ""))
2649  {
2650  TempMapPair.first = Track->TrackElementAt(1060, x).ActiveTrackElementName;
2651  TempMapPair.second = 'x'; // unused
2652  ContinuationNameMap.insert(TempMapPair);
2653  }
2654  }
2655 
2656 //check (provided TrackFinished is true) if any named (red) locations are without platforms, ie concourses only or concourses and foot crossings
2657 //(don't report blue areas without track as these unlikely to be mistakes)
2658 
2659  if(TrackFinished)
2660  {
2661  AnsiString Name = "";
2662  typedef std::list<AnsiString> TNoPlatsList;
2663  TNoPlatsList::iterator NPLIt;
2664  TNoPlatsList NoPlatsList;
2665  typedef std::list<AnsiString> TLocNameList;
2666  TLocNameList LocNameList; //single entry for each name
2669  for(TLocationNameMultiMapIterator LNMMIt = LocationNameMultiMap.begin(); LNMMIt != LocationNameMultiMap.end(); LNMMIt++)
2670  {
2671  LocNameList.push_back(LNMMIt->first);
2672  }
2673  LocNameList.sort();
2674  LocNameList.unique();
2675  for(TLocNameList::iterator LNLIt = LocNameList.begin(); LNLIt != LocNameList.end(); LNLIt++)
2676  {
2677  Name = *LNLIt;
2678  MMRange = LocationNameMultiMap.equal_range(Name);
2679  if(MMRange.first == MMRange.second) //can't find it - should always do but include as a safeguard
2680  {
2681  continue;
2682  }
2683  for(TLocationNameMultiMapIterator LNMMIt = MMRange.first; LNMMIt != MMRange.second; LNMMIt++)
2684  {
2685  if((LNMMIt->second) < 0) //active track element
2686  {
2687  if(TrackElementAt(1401, -1 - LNMMIt->second).TrackType != FootCrossing)
2688  {
2689  break;
2690  }
2691  }
2692  else //inactive
2693  {
2694  if(InactiveTrackElementAt(1402, LNMMIt->second).TrackType != Concourse)
2695  {
2696  break;
2697  }
2698  }
2699  TempIt = MMRange.second;
2700  if(LNMMIt == --TempIt) //reached last named element & all concourses or foot crossings
2701  {
2702  NoPlatsList.push_back(Name);
2703  }
2704  }
2705  }
2706  if(!NoPlatsList.empty())
2707  {
2708  AnsiString NoPlatsAnsiList = "";
2709  for(NPLIt = NoPlatsList.begin(); NPLIt != NoPlatsList.end(); NPLIt++)
2710  {
2711  NoPlatsAnsiList += *NPLIt + '\n';
2712  }
2713  if(!NoPlatsMessageSent)
2714  {
2715  if(NoPlatsList.size() > 1)
2716  {
2717  ShowMessage("Please note: the following locations have no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2718  }
2719  else
2720  {
2721  ShowMessage("Please note: the following location has no platforms, trains won't be able to stop or pass there:-\n\n" + NoPlatsAnsiList + "\nThis message will not be shown again.");
2722  }
2723  NoPlatsMessageSent = true;
2724  }
2725  }
2726  }
2727  Utilities->CallLogPop(440);
2728  return(true);
2729 }
2730 
2731 // ---------------------------------------------------------------------------
2732 bool TTrack::ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
2733 // unused - too time-consuming - double brute force search
2734 {
2735  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErrorInTrackBeforeSetGaps");
2736  int NewHLoc, NewVLoc;
2737  bool ConnectionFoundFlag, LinkFoundFlag;
2738 
2739  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
2740  {
2741  for(unsigned int y = 0; y < 4; y++) // check all links for each element
2742  {
2743  if(TrackElementAt(1061, x).Link[y] <= 0)
2744  {
2745  continue; // no link
2746  }
2747  if(TrackElementAt(1062, x).Config[y] == End)
2748  {
2749  continue; // buffer or continuation
2750  }
2751  if(TrackElementAt(1063, x).Config[y] == Gap)
2752  {
2753  continue; // gap jump
2754  }
2755  // get required H & V for track element joining link 'y'
2756  NewHLoc = TrackElementAt(1064, x).HLoc + LinkHVArray[TrackElementAt(1065, x).Link[y]][0];
2757  NewVLoc = TrackElementAt(1066, x).VLoc + LinkHVArray[TrackElementAt(1067, x).Link[y]][1];
2758  // find track element if present
2759  ConnectionFoundFlag = false;
2760  for(unsigned int z = 0; z < TrackVector.size(); z++)
2761  {
2762 // if(TrackElementAt(5, z).TrackType == Platform)
2763 // continue; //skip platforms
2764  if((TrackElementAt(1068, z).HLoc == NewHLoc) && (TrackElementAt(1069, z).VLoc == NewVLoc))
2765  {
2766  ConnectionFoundFlag = true;
2767  // find connecting link in the newly found track element if there is one
2768  LinkFoundFlag = false;
2769  for(unsigned int a = 0; a < 4; a++)
2770  {
2771  if(TrackElementAt(1070, z).Link[a] == (10 - TrackElementAt(1071, x).Link[y]))
2772  {
2773  LinkFoundFlag = true;
2774  }
2775  }
2776  // if there isn't a corresponding link set the invert values for the offending element
2777  if(!LinkFoundFlag)
2778  {
2779  HLoc = TrackElementAt(1072, x).HLoc;
2780  VLoc = TrackElementAt(1073, x).VLoc;
2781  Utilities->CallLogPop(441);
2782  return(true);
2783  }
2784  break; // success, so break out of 'z' loop
2785  } // if((TrackElementAt(, z).HLoc== NewHLoc) &&....
2786 
2787  } // for z...
2788  // if there isn't a connection set the invert values for the offending element
2789  if(!ConnectionFoundFlag)
2790  {
2791  HLoc = TrackElementAt(1074, x).HLoc;
2792  VLoc = TrackElementAt(1075, x).VLoc;
2793  Utilities->CallLogPop(442);
2794  return(true);
2795  }
2796  } // for y....
2797  } // for x...
2798  Utilities->CallLogPop(443);
2799  return(false); // all OK
2800 }
2801 
2802 // ---------------------------------------------------------------------------
2803 
2804 bool TTrack::FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement) // true if find one
2805 {
2806  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNonPlatformMatch," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
2807  TrackElement.LogTrack(0));
2808  bool FoundFlag;
2809 
2810  Position = GetVectorPositionFromTrackMap(13, HLoc, VLoc, FoundFlag);
2811  if(FoundFlag)
2812  {
2813  TrackElement = TrackElementAt(1076, Position);
2814  }
2815  Utilities->CallLogPop(444);
2816  return(FoundFlag);
2817 }
2818 
2819 // ---------------------------------------------------------------------------
2820 
2822 {
2823  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextTrackElement");
2824  if(NextTrackElementPtr >= TrackVector.end())
2825  {
2826  Utilities->CallLogPop(1336);
2827  return(false);
2828  }
2829  Next = *NextTrackElementPtr;
2831  Utilities->CallLogPop(1337);
2832  return(true);
2833 }
2834 
2835 // ---------------------------------------------------------------------------
2836 
2838 {
2839  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ReturnNextInactiveTrackElement");
2841  {
2842  Utilities->CallLogPop(1338);
2843  return(false);
2844  }
2845  Next = *NextTrackElementPtr;
2847  Utilities->CallLogPop(1339);
2848  return(true);
2849 }
2850 
2851 // ---------------------------------------------------------------------------
2852 
2853 int TTrack::NumberOfGaps(int Caller)
2854 
2855 {
2856  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfGaps");
2857  int Count = 0;
2858 
2859  if(TrackVector.size() == 0)
2860  {
2861  Utilities->CallLogPop(1340);
2862  return(0);
2863  }
2864  for(unsigned int x = 0; x < TrackVector.size(); x++)
2865  {
2866  if(TrackElementAt(1077, x).TrackType == GapJump)
2867  {
2868  Count++;
2869  }
2870  }
2871  Utilities->CallLogPop(1341);
2872  return(Count);
2873 }
2874 
2875 // ---------------------------------------------------------------------------
2877 // above sets all Conns and CLks to -1 except for gapjumps that match and are properly set
2878 // returns true for any unset gaps
2879 {
2880  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetConnClkCheckUnsetGapJumps");
2881  bool UnsetGaps = false;
2882 
2883  if(TrackVector.size() == 0)
2884  {
2885  Utilities->CallLogPop(445);
2886  return(false);
2887  }
2888  for(unsigned int x = 0; x < TrackVector.size(); x++)
2889  {
2890  if(TrackElementAt(1078, x).TrackType != GapJump)
2891  {
2892  for(unsigned int y = 0; y < 4; y++)
2893  {
2894  TrackElementAt(1079, x).Conn[y] = -1;
2895  TrackElementAt(1080, x).ConnLinkPos[y] = -1;
2896  }
2897  }
2898  else // GapJump
2899  {
2900 // int tempint = TrackElementAt(, x).Conn[0);
2901 
2902  if(TrackElementAt(1081, x).Conn[0] == -1) // unset if -1
2903  {
2904  for(unsigned int y = 0; y < 4; y++)
2905  {
2906  TrackElementAt(1082, x).Conn[y] = -1;
2907  TrackElementAt(1083, x).ConnLinkPos[y] = -1;
2908  }
2909  UnsetGaps = true;
2910  continue; // to next 'x'
2911  }
2912  else // set, but may not have matching element, or that element may not be set
2913  {
2914  for(unsigned int y = 1; y < 4; y++) // reset the non-gap values anyway, gap always at position 0
2915  {
2916  TrackElementAt(1084, x).Conn[y] = -1;
2917  TrackElementAt(1085, x).ConnLinkPos[y] = -1;
2918  }
2919 
2920  if(TrackElementAt(1086, TrackElementAt(1104, x).Conn[0]).TrackType != GapJump)
2921  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks & reset Lk[0]
2922  {
2923  for(unsigned int y = 0; y < 4; y++)
2924  {
2925  TrackElementAt(1087, x).Conn[y] = -1;
2926  TrackElementAt(1088, x).ConnLinkPos[y] = -1;
2927  }
2928  UnsetGaps = true;
2929  continue; // to next 'x'
2930  }
2931 // here if gap connection is itself a GapJump
2932  if(TrackElementAt(1089, TrackElementAt(1105, x).Conn[0]).Conn[0] != (int)x)
2933  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
2934  // if not clear Conns & CLks & reset Lk[0]
2935  {
2936  for(unsigned int y = 0; y < 4; y++)
2937  {
2938  TrackElementAt(1090, x).Conn[y] = -1;
2939  TrackElementAt(1091, x).ConnLinkPos[y] = -1;
2940  }
2941  UnsetGaps = true;
2942  continue; // to next 'x'
2943  }
2944 // here if gap connection itself points back to 'x' so these two GapJumps match properly
2945 // hence no more action needed on these Conns & CLks
2946  }
2947  } // else //gap jump
2948 
2949  } // for x...
2950  Utilities->CallLogPop(446);
2951  return(UnsetGaps);
2952 }
2953 
2954 // ---------------------------------------------------------------------------
2955 
2956 void TTrack::LoadTrack(int Caller, std::ifstream& VecFile, bool &GraphicsFollow)
2957 {
2958 // VecFile already open and its pointer at right place on calling
2959  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadTrack");
2960  int TempInt;
2961 
2962  TrackClear(1);
2963 // load track elements
2964  int NumberOfActiveElements = 0;
2965 
2966  GraphicsFollow = false;
2967  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
2968  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // **Active elements** marker, if last character is '1' then there are graphics to be loaded
2969 
2970  if(MarkerString[MarkerString.Length()] == '1')
2971  {
2972  GraphicsFollow = true;
2973  }
2974  for(int x = 0; x < NumberOfActiveElements; x++)
2975  {
2976  VecFile >> TempInt; // TrackVectorNumber, not used
2977  VecFile >> TempInt; // SpeedTag
2978  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
2979  VecFile >> TempInt;
2980  TrackElement.HLoc = TempInt;
2981  VecFile >> TempInt;
2982  TrackElement.VLoc = TempInt;
2983  if(TrackElement.TrackType == GapJump)
2984  {
2985  VecFile >> TempInt;
2986  TrackElement.ConnLinkPos[0] = TempInt;
2987  VecFile >> TempInt;
2988  TrackElement.Conn[0] = TempInt;
2989  }
2990  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
2991  {
2992  VecFile >> TempInt;
2993  TrackElement.Attribute = TempInt;
2994  }
2995  if(TrackElement.TrackType == SignalPost)
2996  {
2997  VecFile >> TempInt;
2998  if(TempInt == 0)
2999  {
3000  TrackElement.CallingOnSet = false;
3001  }
3002  else
3003  {
3004  TrackElement.CallingOnSet = true;
3005  }
3006  }
3007  VecFile >> TempInt;
3008  TrackElement.Length01 = TempInt;
3009  VecFile >> TempInt;
3010  TrackElement.Length23 = TempInt;
3011  VecFile >> TempInt;
3012  if((TempInt != -1) && (TempInt < 10))
3013  {
3014  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3015  }
3016  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3017  {
3018  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3019  }
3020  TrackElement.SpeedLimit01 = TempInt;
3021  VecFile >> TempInt;
3022  if((TempInt != -1) && (TempInt < 10))
3023  {
3024  TempInt = 10; // added at v0.6 to ensure old railway speed limits at least 10km/h
3025  }
3026  if((TempInt != -1) && (TempInt > TTrain::MaximumSpeedLimit))
3027  {
3028  TempInt = TTrain::MaximumSpeedLimit; // added at v2.1.0 to limit max speed
3029  }
3030  TrackElement.SpeedLimit23 = TempInt;
3031 
3032  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3033  TrackElement.ActiveTrackElementName = Utilities->LoadFileString(VecFile);
3034  SetElementID(0, TrackElement);
3035  AnsiString Marker = Utilities->LoadFileString(VecFile); // marker
3036 // new for v0.6
3037  if(TrackElement.TrackType == SignalPost)
3038  {
3039  if(Marker[1] == '3')
3040  {
3041  TrackElement.SigAspect = TTrackElement::ThreeAspect;
3042  }
3043  else if(Marker[1] == '2')
3044  {
3045  TrackElement.SigAspect = TTrackElement::TwoAspect;
3046  }
3047  else if(Marker[1] == 'G')
3048  {
3049  TrackElement.SigAspect = TTrackElement::GroundSignal;
3050  }
3051  else
3052  {
3053  TrackElement.SigAspect = TTrackElement::FourAspect;
3054  }
3055  }
3056  if(TrackElement.SpeedTag != 0)
3057  {
3058  TrackPush(8, TrackElement); // don't save default elements (now dispensed with)
3059  }
3060  }
3061  int NumberOfInactiveElements = 0;
3062 
3063  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3064  Utilities->LoadFileString(VecFile); // **Inactive elements** marker
3065  for(int x = 0; x < NumberOfInactiveElements; x++)
3066  {
3067  VecFile >> TempInt; // InactiveTrackVectorNumber - not used, only used for identification in file
3068  VecFile >> TempInt; // SpeedTag
3069  TTrackElement TrackElement(FixedTrackArray.FixedTrackPiece[TempInt]);
3070  VecFile >> TempInt;
3071  TrackElement.HLoc = TempInt;
3072  VecFile >> TempInt;
3073  TrackElement.VLoc = TempInt;
3074  TrackElement.LocationName = Utilities->LoadFileString(VecFile);
3075  SetElementID(3, TrackElement);
3076  TrackPush(9, TrackElement);
3077  Utilities->LoadFileString(VecFile); // marker
3078  }
3079  bool LocError = false; // needed for TryToConnectTrack but not used
3080  int H = -1, V = -1; // needed for TryToConnectTrack but not used
3081 
3082  if(TryToConnectTrack(2, LocError, H, V, false)) // false for don't give messages
3083  {
3084  SetTrackFinished(true);
3085  }
3086  else
3087  {
3088  SetTrackFinished(false);
3089  }
3090 // CheckMapAndTrack(9); all these checked in TryToConnectTrack
3091 // CheckMapAndInactiveTrack(8);
3092 // CheckLocationNameMultiMap(10);
3093  Utilities->CallLogPop(448);
3094 }
3095 
3096 // ---------------------------------------------------------------------------
3097 
3098 void TTrack::LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3099 {
3100 // VecFile already open and its pointer at right place on calling
3101  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadGraphics, " + GraphicsPath);
3102 // first int is number of graphics, then each graphic, create in UserGraphicMap, derive Width & height from TPicture
3103 // & load into UserGraphicItem then store in UserGraphicVector
3104  UserGraphicVector.clear();
3105  TUserGraphicItem UGI;
3106  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3107 
3108  for(int x = 0; x < NumberOfGraphics; x++)
3109  {
3110  UGI.FileName = GraphicsPath + "\\" + Utilities->LoadFileString(VecFile);
3111  UGI.HPos = Utilities->LoadFileInt(VecFile);
3112  UGI.VPos = Utilities->LoadFileInt(VecFile);
3113  UGI.Width = 0; // provisional value
3114  UGI.Height = 0; // provisional value
3115  UGI.UserGraphic = NULL; // provisional value
3116  UserGraphicVector.push_back(UGI);
3117  }
3118 // now load the map & set Width, Height & TPicture*
3119  bool FileError = false;
3120 
3121  for(int x = 0; x < NumberOfGraphics; x++)
3122  {
3123  if(FileError)
3124  {
3125  break; // otherwise keeps going round the loop
3126  }
3127  UGI = UserGraphicVectorAt(0, x);
3128  if(UserGraphicMap.empty()) // will be when x == 0 but not after
3129  {
3130  try
3131  {
3132 // TUserGraphicMapEntry UGME; //can't define it here, it has to be defined before it is used - now defined in TrackUnit.h
3133  UGME.first = UGI.FileName;
3134  UGME.second = new TPicture;
3135  UGME.second->LoadFromFile(UGME.first); // errors caught below
3136  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3137  {
3138  throw Exception("Map Insertion Error 2 - UserGraphicMap insertion failure for " + UGI.FileName);
3139  }
3140  UGI.UserGraphic = UGME.second;
3141  UGI.Width = UGI.UserGraphic->Width;
3142  UGI.Height = UGI.UserGraphic->Height;
3143  UserGraphicVectorAt(1, x) = UGI;
3144  }
3145  catch(const EInvalidGraphic &e) //non error catch
3146  {
3147  //message already sent in CheckUserGraphics
3148  FileError = true;
3149  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3150  if(!UserGraphicMap.empty())
3151  {
3152  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3153  {
3154  delete UGMIt->second;
3155  }
3156  UserGraphicMap.clear();
3157  }
3158  }
3159  catch(const Exception &e) //non error catch
3160  {
3161  //message already sent in CheckUserGraphics
3162  FileError = true;
3163  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3164  if(!UserGraphicMap.empty())
3165  {
3166  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3167  {
3168  delete UGMIt->second;
3169  }
3170  UserGraphicMap.clear();
3171  }
3172  }
3173  }
3174  else
3175  {
3176  bool FoundInMap = false;
3177  for(TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3178  {
3179  if(UGI.FileName == UGMIt->first) // already exists in map
3180  {
3181  UGI.UserGraphic = UGMIt->second;
3182  UGI.Width = UGI.UserGraphic->Width;
3183  UGI.Height = UGI.UserGraphic->Height;
3184  UserGraphicVectorAt(2, x) = UGI;
3185  FoundInMap = true;
3186  break;
3187  }
3188  }
3189  if(!FoundInMap)
3190  {
3191  try
3192  {
3194  UGME.first = UGI.FileName;
3195  UGME.second = new TPicture;
3196  UGME.second->LoadFromFile(UGME.first); // errors caught below
3197  if(!Track->UserGraphicMap.insert(UGME).second) // if no failure then the new entry is inserted
3198  {
3199  throw Exception("Map Insertion Error 3 - UserGraphicMap insertion failure for " + UGI.FileName);
3200  }
3201  UGI.UserGraphic = UGME.second;
3202  UGI.Width = UGI.UserGraphic->Width;
3203  UGI.Height = UGI.UserGraphic->Height;
3204  UserGraphicVectorAt(3, x) = UGI;
3205  }
3206  catch(const EInvalidGraphic &e) //non error catch
3207  {
3208  //message already sent in CheckUserGraphics
3209  FileError = true;
3210  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3211  if(!UserGraphicMap.empty())
3212  {
3213  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3214  {
3215  delete UGMIt->second;
3216  }
3217  UserGraphicMap.clear();
3218  }
3219  }
3220  catch(const Exception &e) //non error catch
3221  {
3222  //message already sent in CheckUserGraphics
3223  FileError = true;
3224  UserGraphicVector.clear(); // so doesn't try to plot non-existent graphics
3225  if(!UserGraphicMap.empty())
3226  {
3227  for(TTrack::TUserGraphicMap::iterator UGMIt = UserGraphicMap.begin(); UGMIt != UserGraphicMap.end(); UGMIt++)
3228  {
3229  delete UGMIt->second;
3230  }
3231  UserGraphicMap.clear();
3232  }
3233  }
3234  }
3235  }
3236  }
3237  Utilities->CallLogPop(2167);
3238 }
3239 
3240 // ---------------------------------------------------------------------------
3241 
3242 void TTrack::SaveTrack(int Caller, std::ofstream& VecFile, bool GraphicsFollow)
3243 {
3244 // VecFile already open and its pointer at right place on calling
3245 // if GraphicsFollow true, then save Marker as **Active elements**1
3246 // save trackfinished flag
3247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveTrack, " + AnsiString(int(GraphicsFollow)));
3248  TTrackElement TrackElement, InactiveTrackElement;
3249 
3250 // save track elements
3251  Utilities->SaveFileInt(VecFile, TrackVector.size());
3252  if(GraphicsFollow)
3253  {
3254  VecFile << "**Active elements**1" << '\0' << '\n';
3255  }
3256  else
3257  {
3258  VecFile << "**Active elements**" << '\0' << '\n';
3259  }
3260  for(unsigned int x = 0; x < (TrackVector.size()); x++)
3261  {
3262  TrackElement = TrackElementAt(1092, x);
3263  VecFile << x << '\n'; // this is the TrackVectorNumber - extra, so easier to identify in the file
3264  VecFile << TrackElement.SpeedTag << '\n';
3265  VecFile << TrackElement.HLoc << '\n';
3266  VecFile << TrackElement.VLoc << '\n';
3267  if(TrackElement.TrackType == GapJump)
3268  {
3269  VecFile << TrackElement.ConnLinkPos[0] << '\n';
3270  VecFile << TrackElement.Conn[0] << '\n';
3271  }
3272  if((TrackElement.TrackType == SignalPost) || (TrackElement.TrackType == Points))
3273  {
3274  VecFile << TrackElement.Attribute << '\n';
3275  }
3276  if(TrackElement.TrackType == SignalPost)
3277  {
3278  if(TrackElement.CallingOnSet)
3279  {
3280  VecFile << int(1) << '\n';
3281  }
3282  else
3283  {
3284  VecFile << int(0) << '\n';
3285  }
3286  }
3287  VecFile << TrackElement.Length01 << '\n';
3288  VecFile << TrackElement.Length23 << '\n';
3289  VecFile << TrackElement.SpeedLimit01 << '\n';
3290  VecFile << TrackElement.SpeedLimit23 << '\n';
3291  VecFile << TrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3292  VecFile << TrackElement.ActiveTrackElementName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3293 // new for v0.6
3294  if(TrackElement.TrackType == SignalPost)
3295  {
3296  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
3297  {
3298  VecFile << "3*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3299  }
3300  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
3301  {
3302  VecFile << "2*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3303  }
3304  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
3305  {
3306  VecFile << "G*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3307  }
3308  else // 4 aspect
3309  {
3310  VecFile << "4*****" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3311  }
3312  }
3313  else
3314  {
3315  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3316  }
3317  }
3318 
3319  Utilities->SaveFileInt(VecFile, InactiveTrackVector.size());
3320  VecFile << "**Inactive elements**" << '\0' << '\n'; // extra
3321  for(unsigned int x = 0; x < (InactiveTrackVector.size()); x++)
3322  {
3323  InactiveTrackElement = InactiveTrackElementAt(136, x);
3324  VecFile << x << '\n'; // this is the Inactive TrackVectorNumber - extra
3325  VecFile << InactiveTrackElement.SpeedTag << '\n';
3326  VecFile << InactiveTrackElement.HLoc << '\n';
3327  VecFile << InactiveTrackElement.VLoc << '\n';
3328  VecFile << InactiveTrackElement.LocationName.c_str() << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3329  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
3330  }
3331  Utilities->CallLogPop(449);
3332 }
3333 
3334 // ---------------------------------------------------------------------------
3335 
3336 bool TTrack::CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream& VecFile)
3337 {
3338 // VecFile already open and its pointer at right place on calling
3339 // check trackfinished flag
3340 // inactive elements follow immediately after active elements, no need to check for a marker between them
3341  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckTrackElementsInFile");
3342  int TempInt;
3343 
3344  GraphicsFollow = false;
3345  NumberOfActiveElements = Utilities->LoadFileInt(VecFile);
3346  if((NumberOfActiveElements < 0) || (NumberOfActiveElements > 1000000)) // No of active elements (up to 500 screens all completely full!)
3347  {
3348  Utilities->CallLogPop(1513);
3349  return(false);
3350  }
3351 // if(!Utilities->CheckAndCompareFileString(VecFile, "**Active elements**")) dropped at v2.4.0 as could have a '1' at the end if there are graphics
3352  AnsiString MarkerString;
3353 
3354  if(!Utilities->CheckAndReadFileString(VecFile, MarkerString)) // new version for v2.4.0
3355  {
3356  Utilities->CallLogPop(1758);
3357  return(false);
3358  }
3359  if(MarkerString[MarkerString.Length()] == '1')
3360  {
3361  GraphicsFollow = true;
3362  }
3363  for(int x = 0; x < NumberOfActiveElements; x++)
3364  {
3365  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3366  {
3367  Utilities->CallLogPop(1759);
3368  return(false);
3369  }
3370  VecFile >> TempInt;
3371  int SpeedTag = TempInt;
3372  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3373  {
3374  Utilities->CallLogPop(1514);
3375  return(false);
3376  }
3377  VecFile >> TempInt;
3378  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3379  {
3380  Utilities->CallLogPop(1495);
3381  return(false);
3382  }
3383  VecFile >> TempInt;
3384  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3385  {
3386  Utilities->CallLogPop(1497);
3387  return(false);
3388  }
3389  if((SpeedTag > 87) && (SpeedTag < 96)) // GapJumps 88-95 incl
3390  {
3391  VecFile >> TempInt;
3392  if((TempInt < -1) || (TempInt > 3)) // ConnLinkPos[0]
3393  {
3394  Utilities->CallLogPop(1499);
3395  return(false);
3396  }
3397  VecFile >> TempInt;
3398  if((TempInt < -1) || (TempInt > 999999)) // Conn[0]
3399  {
3400  Utilities->CallLogPop(1500);
3401  return(false);
3402  }
3403  }
3404  if(((SpeedTag >= 7) && (SpeedTag <= 14)) || ((SpeedTag >= 28) && (SpeedTag <= 43)) || ((SpeedTag >= 132) && (SpeedTag <= 139)) ||
3405  ((SpeedTag >= 68) && (SpeedTag <= 75)))
3406  {
3407  VecFile >> TempInt;
3408  if((TempInt < -1) || (TempInt > 5)) // Points & signal attribute
3409  {
3410  Utilities->CallLogPop(1502);
3411  return(false);
3412  }
3413  }
3414  if((SpeedTag >= 68) && (SpeedTag <= 75)) // signals
3415  {
3416  VecFile >> TempInt;
3417  if((TempInt != 0) && (TempInt != 1)) // CallingOnSet
3418  {
3419  Utilities->CallLogPop(1155);
3420  return(false);
3421  }
3422  }
3423  VecFile >> TempInt;
3424  if((TempInt < -1) || (TempInt > 999999)) // Length01
3425  {
3426  Utilities->CallLogPop(1503);
3427  return(false);
3428  }
3429  VecFile >> TempInt;
3430  if((TempInt < -1) || (TempInt > 999999)) // Length23
3431  {
3432  Utilities->CallLogPop(1504);
3433  return(false);
3434  }
3435  VecFile >> TempInt;
3436  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit01
3437  {
3438  Utilities->CallLogPop(1505);
3439  return(false);
3440  }
3441  VecFile >> TempInt;
3442  if((TempInt < -1) || (TempInt > 999999)) // SpeedLimit23
3443  {
3444  Utilities->CallLogPop(1506);
3445  return(false);
3446  }
3447  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3448  {
3449  Utilities->CallLogPop(1142);
3450  return(false); // LocationName
3451  }
3452  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3453  {
3454  Utilities->CallLogPop(1143);
3455  return(false); // ActiveTrackElementName
3456  }
3457  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3458  {
3459  Utilities->CallLogPop(1787);
3460  return(false); // marker
3461  }
3462  }
3463  int NumberOfInactiveElements = 0;
3464 
3465  NumberOfInactiveElements = Utilities->LoadFileInt(VecFile);
3466  if(NumberOfInactiveElements < 0) // No of active elements
3467  {
3468  Utilities->CallLogPop(1493);
3469  return(false);
3470  }
3471  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3472  {
3473  Utilities->CallLogPop(1764);
3474  return(false); // **Inactive elements** marker
3475  }
3476  for(int x = 0; x < NumberOfInactiveElements; x++)
3477  {
3478  if(!Utilities->CheckFileInt(VecFile, x, x)) // TrackVectorNumber, must be 'x'
3479  {
3480  Utilities->CallLogPop(1765);
3481  return(false);
3482  }
3483  VecFile >> TempInt;
3484  if((TempInt < 0) || (TempInt >= FirstUnusedSpeedTagNumber) || (TempInt == 17)) // Speedtag
3485  {
3486  Utilities->CallLogPop(1494);
3487  return(false);
3488  }
3489  VecFile >> TempInt;
3490  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // HLoc
3491  {
3492  Utilities->CallLogPop(1496);
3493  return(false);
3494  }
3495  VecFile >> TempInt;
3496  if(((TempInt > 999999) || (TempInt < -1000001)) && (TempInt != -2000000000)) // VLoc
3497  {
3498  Utilities->CallLogPop(1498);
3499  return(false);
3500  }
3501  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3502  {
3503  Utilities->CallLogPop(1144);
3504  return(false); // LocationName
3505  }
3506  if(!(Utilities->CheckFileStringZeroDelimiter(VecFile)))
3507  {
3508  Utilities->CallLogPop(1788);
3509  return(false); // marker
3510  }
3511  }
3512  Utilities->CallLogPop(1507);
3513  return(true);
3514 }
3515 
3516 // ---------------------------------------------------------------------------
3517 
3518 bool TTrack::CheckUserGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
3519 {
3520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckUserGraphics");
3521  int NumberOfGraphics = Utilities->LoadFileInt(VecFile);
3522 
3523  if((NumberOfGraphics < 0) || (NumberOfGraphics > 100000)) // 100,000 should be plenty!
3524  {
3525  Utilities->CallLogPop(2168);
3526  return(false);
3527  }
3528  // filename in Graphics folder, then HPos, then VPos
3529  AnsiString FileName = "", TempStr = "";
3530 
3531  for(int x = 0; x < NumberOfGraphics; x++)
3532  {
3533  TPicture *TempPicture = new TPicture;
3534  try
3535  {
3536  if(!Utilities->CheckAndReadFileString(VecFile, FileName))
3537  {
3538  Utilities->CallLogPop(2169);
3539  delete TempPicture;
3540  return(false);
3541  }
3542  TempPicture->LoadFromFile(GraphicsPath + "\\" + FileName); // only loaded to check and catch errors
3543  delete TempPicture;
3544  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // HPos, allow plenty of scope
3545  {
3546  Utilities->CallLogPop(2170);
3547  return(false);
3548  }
3549  if(!Utilities->CheckFileInt(VecFile, -2000000, 2000000)) // VPos
3550  {
3551  Utilities->CallLogPop(2171);
3552  return(false);
3553  }
3554  }
3555  catch(const EInvalidGraphic &e) //non error catch
3556  {
3557  //move file pointer to end of graphic section for later checks in session files
3558  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3559  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3560  for(int y = x + 1; y < NumberOfGraphics; y++)
3561  {
3562  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3563  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3564  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3565  }
3566  ShowMessage(FileName +
3567  " has an incorrect file format, user graphics can't be loaded. Ensure that all user graphic files are valid with extension .bmp, .gif, .jpg, or .png");
3568  Utilities->CallLogPop(2172);
3569  delete TempPicture;
3570  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3571  }
3572  catch(const Exception &e) //non error catch
3573  {
3574  //move file pointer to end of graphic section for later checks in session files
3575  Utilities->CheckAndReadFileString(VecFile, TempStr); //get rid of HPos
3576  Utilities->CheckAndReadFileString(VecFile, TempStr); //VPos
3577  for(int y = x + 1; y < NumberOfGraphics; y++)
3578  {
3579  Utilities->CheckAndReadFileString(VecFile, TempStr); //next FileName
3580  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3581  Utilities->CheckAndReadFileString(VecFile, TempStr); //next VPos
3582  }
3583  ShowMessage("Unable to load user graphic files, ensure that " + FileName +
3584  " exists in the 'Graphics' folder and that it is has extension .bmp, .gif, .jpg, or .png.");
3585  Utilities->CallLogPop(2173);
3586  delete TempPicture;
3587  return(true); //for these file errors allow railway or session to be loaded, changed at v2.6.0
3588  }
3589  }
3590  Utilities->CallLogPop(2174);
3591  return(true);
3592 }
3593 
3594 // ---------------------------------------------------------------------------
3595 
3596 void TTrack::SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
3597 {
3598  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSessionBarriersDownVector");
3599  int VecSize = Track->BarriersDownVector.size();
3600 
3601  Utilities->SaveFileInt(OutFile, VecSize);
3602  for(int x = 0; x < VecSize; x++)
3603  {
3605  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3606  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3607  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3608  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3609  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3610  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3611  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3612  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3613  }
3614  Utilities->CallLogPop(1963);
3615 }
3616 
3617 // ---------------------------------------------------------------------------
3618 
3619 void TTrack::SaveChangingLCVector(int Caller, std::ofstream &OutFile) //used only in errorfile
3620 {
3621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveChangingLCVector");
3622  int VecSize = Track->ChangingLCVector.size();
3623 
3624  Utilities->SaveFileInt(OutFile, VecSize);
3625  for(int x = 0; x < VecSize; x++)
3626  {
3628  Utilities->SaveFileInt(OutFile, TALC.TypeOfRoute); //changed to int from bool in v2.6.0
3629  Utilities->SaveFileBool(OutFile, TALC.ReducedTimePenalty);
3630  Utilities->SaveFileInt(OutFile, (short)TALC.BarrierState);
3631  Utilities->SaveFileDouble(OutFile, TALC.ChangeDuration);
3632  Utilities->SaveFileInt(OutFile, TALC.BaseElementSpeedTag);
3633  Utilities->SaveFileInt(OutFile, TALC.HLoc);
3634  Utilities->SaveFileInt(OutFile, TALC.VLoc);
3635  Utilities->SaveFileDouble(OutFile, double(TALC.StartTime));
3636  }
3637  Utilities->CallLogPop(1980);
3638 }
3639 
3640 // ---------------------------------------------------------------------------
3641 
3642 bool TTrack::CheckActiveLCVector(int Caller, std::ifstream &VecFile)
3643 {
3644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckActiveLCVector");
3645  int VecSize = Utilities->LoadFileInt(VecFile);
3646 
3647  for(int x = 0; x < VecSize; x++)
3648  {
3649  if(!Utilities->CheckFileInt(VecFile, 0, 2)) //changed from bool at v2.6.0 to allow TypeOfRoute == 2 for barriers manually lowered
3650  {
3651  Utilities->CallLogPop(1970);
3652  return(false);
3653  }
3654  if(!Utilities->CheckFileBool(VecFile))
3655  {
3656  Utilities->CallLogPop(1971);
3657  return(false);
3658  }
3659  if(!Utilities->CheckFileInt(VecFile, 0, 3))
3660  {
3661  Utilities->CallLogPop(1972);
3662  return(false);
3663  }
3664  if(!Utilities->CheckFileDouble(VecFile))
3665  {
3666  Utilities->CallLogPop(1973);
3667  return(false);
3668  }
3669  if(!Utilities->CheckFileInt(VecFile, 1, 2))
3670  {
3671  Utilities->CallLogPop(1974);
3672  return(false);
3673  }
3674  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3675  {
3676  Utilities->CallLogPop(1975);
3677  return(false);
3678  }
3679  if(!Utilities->CheckFileInt(VecFile, -1000001, 999999))
3680  {
3681  Utilities->CallLogPop(1976);
3682  return(false);
3683  }
3684  if(!Utilities->CheckFileDouble(VecFile))
3685  {
3686  Utilities->CallLogPop(1977);
3687  return(false);
3688  }
3689  }
3690  Utilities->CallLogPop(1978);
3691  return(true);
3692 }
3693 
3694 // ---------------------------------------------------------------------------
3695 
3696 void TTrack::LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
3697 {
3698  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadBarriersDownVector");
3699  int VecSize = Utilities->LoadFileInt(VecFile);
3700 
3701  for(int x = 0; x < VecSize; x++)
3702  {
3703  TActiveLevelCrossing TALC;
3704  TALC.TypeOfRoute = Utilities->LoadFileInt(VecFile); //changed to int from bool in v2.6.0
3705  TALC.ReducedTimePenalty = Utilities->LoadFileBool(VecFile);
3706  TALC.BarrierState = TBarrierState(Utilities->LoadFileInt(VecFile));
3707  TALC.ChangeDuration = Utilities->LoadFileDouble(VecFile);
3708  TALC.BaseElementSpeedTag = Utilities->LoadFileInt(VecFile);
3709  TALC.HLoc = Utilities->LoadFileInt(VecFile);
3710  TALC.VLoc = Utilities->LoadFileInt(VecFile);
3711  TALC.StartTime = TDateTime(Utilities->LoadFileDouble(VecFile));
3712  BarriersDownVector.push_back(TALC);
3713  }
3714  Utilities->CallLogPop(1979);
3715 }
3716 
3717 // ---------------------------------------------------------------------------
3718 
3719 void TTrack::RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
3720 /*
3721  Note, have to plot inactives before track because track has to overwrite NamedNonStationLocations, but, plot basic LC's (if flag set) after track
3722  so they lie above the track. Basic LCs are plotted for all but Level1Mode == OperMode (i.e. closed to trains), because the LC attributes will always be
3723  0 in such cases and because in OperMode the LCs have to be plotted again after the routes, which is done in Clearand....
3724 */
3725 {
3726  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildTrackAndText," + AnsiString((short)BothPointFilletsAndBasicLCs));
3727  TTrackElement Next;
3728 
3729 // Disp->ClearDisplay();
3731  while(ReturnNextInactiveTrackElement(0, Next))
3732  {
3733  if(Next.TrackType != LevelCrossing) // don't plot level crossings as these need to be plotted after the track
3734  {
3735  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3736  {
3737  // only plot if on screen, to save time
3738  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3740  {
3741  Next.PlotVariableTrackElement(2, Disp); // striped if not named
3742  }
3743  }
3744  }
3745  }
3746 
3747  TextHandler->RebuildFromTextVector(1, Disp); // plot text after inactives so can have text on stations etc
3748 
3749  NextTrackElementPtr = TrackVector.begin();
3750  while(ReturnNextTrackElement(0, Next))
3751  {
3752  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3753  {
3754  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3756  {
3757  if(Next.TrackType == Points)
3758  {
3759  PlotPoints(5, Next, Disp, BothPointFilletsAndBasicLCs);
3760  }
3761  else if(Next.TrackType == SignalPost)
3762  {
3763  PlotSignal(9, Next, Disp);
3764  }
3765  else if(Next.TrackType == GapJump)
3766  {
3767  PlotGap(0, Next, Disp);
3768  }
3769  else
3770  {
3771  Next.PlotVariableTrackElement(3, Disp); // for footcrossings, may be striped or not
3772  }
3773  }
3774  }
3775  }
3776 
3777  if(BothPointFilletsAndBasicLCs)
3778  {
3780  while(ReturnNextInactiveTrackElement(4, Next))
3781  {
3782  if(Next.TrackType == LevelCrossing) // plot level crossings (if required) after the track
3783  {
3784  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3785  {
3786  // only plot if on screen, to save time, & OK as plotting one by one here
3787  if(((Next.HLoc - Display->DisplayOffsetH) >= 0) && ((Next.HLoc - Display->DisplayOffsetH) < Utilities->ScreenElementWidth) &&
3789  {
3790  if(GetTrackElementFromTrackMap(1, Next.HLoc, Next.VLoc).SpeedTag == 1)
3791  {
3792  Disp->PlotOutput(193, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothVer);
3793  }
3794  else
3795  {
3796  Disp->PlotOutput(194, (Next.HLoc * 16), (Next.VLoc * 16), RailGraphics->LCBothHor);
3797  }
3798  }
3799  }
3800  }
3801  }
3802  }
3803  Disp->Update();
3804  Utilities->CallLogPop(468);
3805 }
3806 
3807 // ---------------------------------------------------------------------------
3808 
3809 void TTrack::RebuildUserGraphics(int Caller, TDisplay *Disp) // new at v2.4.0
3810 {
3811  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildUserGraphics,");
3812  if(UserGraphicVector.empty())
3813  {
3814  Utilities->CallLogPop(2175);
3815  return;
3816  }
3817  TUserGraphicItem UGI;
3818 
3819  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
3820  {
3821  UGI = UserGraphicVectorAt(4, x);
3822  if(((UGI.HPos + UGI.Width - (Display->DisplayOffsetH * 16)) >= 0) && ((UGI.HPos - (Display->DisplayOffsetH * 16)) <
3823  (Utilities->ScreenElementWidth * 16)) && ((UGI.VPos + UGI.Height - (Display->DisplayOffsetV * 16)) >= 0) &&
3824  ((UGI.VPos - (Display->DisplayOffsetV * 16)) < (Utilities->ScreenElementHeight * 16)))
3825  {
3826  Disp->PlotAndAddUserGraphic(0, UGI);
3827  }
3828  }
3829  Disp->Update();
3830  Utilities->CallLogPop(2176);
3831 }
3832 
3833 // ---------------------------------------------------------------------------
3834 
3835 void TTrack::WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap) //added text after inactives at v2.10.0
3836 /*
3837  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
3838 */
3839 {
3840  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteTrackAndTextToImage");
3841 // need to change graphics back to black on white if have a dark background
3842  TColor OldTransparentColour = Utilities->clTransparent;
3843 
3845  {
3846  Utilities->clTransparent = TColor(0xFFFFFF); // white
3849  }
3850  TTrackElement Next;
3851 
3852  Bitmap->Canvas->CopyMode = cmSrcCopy;
3854  Graphics::TBitmap *GraphicOutput;
3855 
3856  while(ReturnNextInactiveTrackElement(2, Next))
3857  {
3858  GraphicOutput = Next.GraphicPtr;
3859  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3860  {
3861  if(Next.LocationName == "") // plot as named or unnamed (striped)
3862  {
3863  // default is not striped
3864  switch(Next.SpeedTag)
3865  {
3866  case 76: // t platform
3867  GraphicOutput = RailGraphics->gl76Striped;
3868  break;
3869 
3870  case 77: // h platform
3871  GraphicOutput = RailGraphics->bm77Striped;
3872  break;
3873 
3874  case 78: // v platform
3875  GraphicOutput = RailGraphics->bm78Striped;
3876  break;
3877 
3878  case 79: // r platform
3879  GraphicOutput = RailGraphics->gl79Striped;
3880  break;
3881 
3882  case 96: // concourse
3883  GraphicOutput = RailGraphics->ConcourseStriped;
3884  break;
3885 
3886  case 129: // v footbridge
3887  GraphicOutput = RailGraphics->gl129Striped;
3888  break;
3889 
3890  case 130: // h footbridge
3891  GraphicOutput = RailGraphics->gl130Striped;
3892  break;
3893 
3894  case 131: // non-station named loc
3895  GraphicOutput = RailGraphics->bmNameStriped;
3896  break;
3897 
3898  case 145: // v underpass
3899  GraphicOutput = RailGraphics->gl145Striped;
3900  break;
3901 
3902  case 146: // h underpass
3903  GraphicOutput = RailGraphics->gl146Striped;
3904  break;
3905 
3906  default:
3907  GraphicOutput = Next.GraphicPtr;
3908  break;
3909  }
3910  }
3911  if(Next.SpeedTag == 144) // level crossing
3912  {
3913  if(GetTrackElementFromTrackMap(2, Next.HLoc, Next.VLoc).SpeedTag == 1)
3914  {
3915  GraphicOutput = RailGraphics->LCBothVer;
3916  }
3917  else
3918  {
3919  GraphicOutput = RailGraphics->LCBothHor;
3920  }
3921  }
3922  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
3923  }
3924  }
3925 
3926  TextHandler->WriteTextToImage(0, Bitmap); //so overwrites inactive elements //added at v2.10.0
3927 
3928 
3929  NextTrackElementPtr = TrackVector.begin();
3930  while(ReturnNextTrackElement(2, Next))
3931  {
3932  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
3933  {
3934  if(Next.TrackType == Points) // plot both fillets
3935  {
3936  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
3937  if(Next.SpeedTag < 28)
3938  {
3939  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3941  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3943  }
3944  else if(Next.SpeedTag < 132)
3945  {
3946  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3947  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][0]);
3948  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3949  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 20][1]);
3950  }
3951  else
3952  {
3953  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3954  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][0]);
3955  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
3956  RailGraphics->PointModeGraphicsPtr[Next.SpeedTag - 108][1]);
3957  }
3958  }
3959  else if(Next.TrackType == GapJump) // plot as connected or unconnected
3960  {
3961  if((Next.SpeedTag == 88) && (Next.Conn[0] > -1))
3962  {
3963  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
3964  }
3965  else if((Next.SpeedTag == 88) && (Next.Conn[0] == -1))
3966  {
3967  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88unset);
3968  }
3969  if((Next.SpeedTag == 89) && (Next.Conn[0] > -1))
3970  {
3971  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
3972  }
3973  else if((Next.SpeedTag == 89) && (Next.Conn[0] == -1))
3974  {
3975  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89unset);
3976  }
3977  if((Next.SpeedTag == 90) && (Next.Conn[0] > -1))
3978  {
3979  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
3980  }
3981  else if((Next.SpeedTag == 90) && (Next.Conn[0] == -1))
3982  {
3983  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90unset);
3984  }
3985  if((Next.SpeedTag == 91) && (Next.Conn[0] > -1))
3986  {
3987  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
3988  }
3989  else if((Next.SpeedTag == 91) && (Next.Conn[0] == -1))
3990  {
3991  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91unset);
3992  }
3993  if((Next.SpeedTag == 92) && (Next.Conn[0] > -1))
3994  {
3995  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
3996  }
3997  else if((Next.SpeedTag == 92) && (Next.Conn[0] == -1))
3998  {
3999  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92unset);
4000  }
4001  if((Next.SpeedTag == 93) && (Next.Conn[0] > -1))
4002  {
4003  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4004  }
4005  else if((Next.SpeedTag == 93) && (Next.Conn[0] == -1))
4006  {
4007  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93unset);
4008  }
4009  if((Next.SpeedTag == 94) && (Next.Conn[0] > -1))
4010  {
4011  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4012  }
4013  else if((Next.SpeedTag == 94) && (Next.Conn[0] == -1))
4014  {
4015  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94unset);
4016  }
4017  if((Next.SpeedTag == 95) && (Next.Conn[0] > -1))
4018  {
4019  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4020  }
4021  else if((Next.SpeedTag == 95) && (Next.Conn[0] == -1))
4022  {
4023  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95unset);
4024  }
4025  }
4026  // below added for version 0.6, only stop signals to be drawn
4027  else if(Next.TrackType == SignalPost)
4028  {
4029  for(int x = 0; x < 40; x++)
4030  {
4031  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 0)) // need to plot as red regardless of actual attribute value
4032  {
4033  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4034  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4035  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4036  int HOffset = 0;
4037  if(Next.SpeedTag > 73)
4038  {
4039  HOffset = 5;
4040  }
4041  else if(Next.SpeedTag == 71)
4042  {
4043  HOffset = 9;
4044  }
4045  int VOffset = 0;
4046  if(Next.SpeedTag == 69)
4047  {
4048  VOffset = 9;
4049  }
4050  else if(Next.SpeedTag == 72)
4051  {
4052  VOffset = 5;
4053  }
4054  else if(Next.SpeedTag == 74)
4055  {
4056  VOffset = 5;
4057  }
4058  Graphics::TBitmap *GraphicPtr;
4059  if(Next.SpeedTag > 71)
4060  {
4061  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4062  }
4063  else if(Next.SpeedTag < 70)
4064  {
4065  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4066  }
4067  else
4068  {
4069  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4070  }
4071  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4072  // plot special signal platform if present
4073  Graphics::TBitmap* SignalPlatformGraphic;
4074  if(PlatformOnSignalSide(2, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic)) //
4075  {
4076  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4077  }
4078  // now plot signal (double yellow overwrites most of signal platform if present)
4079  // below amended for version 0.6
4081  {
4082  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4083  }
4084  else if(Next.SigAspect == TTrackElement::TwoAspect)
4085  {
4086  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4087  }
4088  else if(Next.SigAspect == TTrackElement::GroundSignal)
4089  {
4090  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4091  }
4092  else // 4 aspect
4093  {
4094  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4095  }
4096  break;
4097  }
4098  }
4099  }
4100  else
4101  {
4102  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4103  }
4104  }
4105  }
4106  if(OldTransparentColour != clB5G5R5)
4107  {
4108  Utilities->clTransparent = OldTransparentColour; // restore
4111  }
4112  Utilities->CallLogPop(1533);
4113 }
4114 
4115 // ---------------------------------------------------------------------------
4116 
4117 void TTrack::WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
4118 {
4119  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteGraphicsToImage");
4120  if(UserGraphicVector.empty())
4121  {
4122  Utilities->CallLogPop(2192);
4123  return;
4124  }
4125  else
4126  {
4127  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
4128  {
4129  Bitmap->Canvas->CopyMode = cmSrcCopy;
4130  Bitmap->Canvas->Draw(UserGraphicVectorAt(26, x).HPos - (GetHLocMin() * 16), UserGraphicVectorAt(27, x).VPos - (GetVLocMin() * 16),
4131  UserGraphicVectorAt(28, x).UserGraphic->Graphic);
4132  }
4133  }
4134  Utilities->CallLogPop(2193);
4135 }
4136 
4137 // ---------------------------------------------------------------------------
4138 
4139 void TTrack::WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
4140 /*
4141  Note, have to plot inactives before track because track has to overwrite 'name' platforms (NamedLocationElements)
4142  Here plot all named elements as non-striped, points with active fillet, signals as they are set, and gaps as connected
4143 */
4144 {
4145  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteOperatingTrackAndTextToImage");
4146 // need to change graphics back to black on white if have a dark background
4147  TColor OldTransparentColour = Utilities->clTransparent;
4148 
4150  {
4151  Utilities->clTransparent = TColor(0xFFFFFF); // white
4154  }
4155  TTrackElement Next;
4156 
4157  Bitmap->Canvas->CopyMode = cmSrcCopy;
4159  Graphics::TBitmap *GraphicOutput;
4160 
4161  while(ReturnNextInactiveTrackElement(3, Next))
4162  {
4163  GraphicOutput = Next.GraphicPtr; // no striped name graphics
4164  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4165  {
4166  if(Next.SpeedTag == 144) // level crossing
4167  {
4168  int BaseElement = GetTrackElementFromTrackMap(3, Next.HLoc, Next.VLoc).SpeedTag;
4169  if(BaseElement == 1) // hor element
4170  {
4171  if(Next.Attribute == 1) // open to trains
4172  {
4173  GraphicOutput = RailGraphics->LCBothHor;
4174  }
4175  else // plot as closed to trains if in any other state
4176  {
4177  GraphicOutput = RailGraphics->LCBothVer;
4178  }
4179  }
4180  else // vert element
4181  {
4182  if(Next.Attribute == 1) // open to trains
4183  {
4184  GraphicOutput = RailGraphics->LCBothVer;
4185  }
4186  else // plot as closed to trains if in any other state
4187  {
4188  GraphicOutput = RailGraphics->LCBothHor;
4189  }
4190  }
4191  }
4192  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), GraphicOutput);
4193  }
4194  }
4195 
4196  TextHandler->WriteTextToImage(1, Bitmap); //added at v2.10.0
4197 
4198  NextTrackElementPtr = TrackVector.begin();
4199  while(ReturnNextTrackElement(3, Next))
4200  {
4201  if(Next.GraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
4202  {
4203  if(Next.TrackType == Points) // plot active fillet
4204  {
4205  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4206  if(Next.SpeedTag < 28)
4207  {
4208  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4210  }
4211  else if(Next.SpeedTag < 132)
4212  {
4213  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4215  }
4216  else
4217  {
4218  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16),
4220  }
4221  }
4222  else if(Next.TrackType == GapJump) // plot as connected
4223  {
4224  if(Next.SpeedTag == 88)
4225  {
4226  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl88set);
4227  }
4228  else if(Next.SpeedTag == 89)
4229  {
4230  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl89set);
4231  }
4232  else if(Next.SpeedTag == 90)
4233  {
4234  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl90set);
4235  }
4236  else if(Next.SpeedTag == 91)
4237  {
4238  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl91set);
4239  }
4240  else if(Next.SpeedTag == 92)
4241  {
4242  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl92set);
4243  }
4244  else if(Next.SpeedTag == 93)
4245  {
4246  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm93set);
4247  }
4248  else if(Next.SpeedTag == 94)
4249  {
4250  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->bm94set);
4251  }
4252  else if(Next.SpeedTag == 95)
4253  {
4254  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), RailGraphics->gl95set);
4255  }
4256  }
4257  else if(Next.TrackType == SignalPost) // plot in correct colour
4258  {
4259  for(int x = 0; x < 40; x++)
4260  {
4261  if((SigTable[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == Next.Attribute))
4262  {
4263  // plot blank first, then plot platform if present - (always not striped for operating railway)
4264  // note these blanks plotted on lh signal side, even for rh signals, but works ok because the platform is replotted
4265  // in PlatformOnSignalSide, which return true for platform NOT on signal side for rh sigs
4266  int HOffset = 0;
4267  if(Next.SpeedTag > 73)
4268  {
4269  HOffset = 5;
4270  }
4271  else if(Next.SpeedTag == 71)
4272  {
4273  HOffset = 9;
4274  }
4275  int VOffset = 0;
4276  if(Next.SpeedTag == 69)
4277  {
4278  VOffset = 9;
4279  }
4280  else if(Next.SpeedTag == 72)
4281  {
4282  VOffset = 5;
4283  }
4284  else if(Next.SpeedTag == 74)
4285  {
4286  VOffset = 5;
4287  }
4288  Graphics::TBitmap *GraphicPtr;
4289  if(Next.SpeedTag > 71)
4290  {
4291  GraphicPtr = RailGraphics->bmDiagonalSignalBlank;
4292  }
4293  else if(Next.SpeedTag < 70)
4294  {
4295  GraphicPtr = RailGraphics->bmStraightNSSignalBlank;
4296  }
4297  else
4298  {
4299  GraphicPtr = RailGraphics->bmStraightEWSignalBlank;
4300  }
4301  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16) + HOffset, ((Next.VLoc - GetVLocMin()) * 16) + VOffset, GraphicPtr);
4302  // plot special signal platform if present
4303  Graphics::TBitmap* SignalPlatformGraphic;
4304  if(PlatformOnSignalSide(1, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4305  {
4306  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4307  }
4308  // now plot signal (double yellow overwrites most of signal platform if present)
4309  // below amended for version 0.6
4311  {
4312  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableThreeAspect[x].SigPtr);
4313  }
4314  else if(Next.SigAspect == TTrackElement::TwoAspect)
4315  {
4316  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableTwoAspect[x].SigPtr);
4317  }
4318  else if(Next.SigAspect == TTrackElement::GroundSignal)
4319  {
4320  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4321  }
4322  else // 4 aspect
4323  {
4324  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTable[x].SigPtr);
4325  }
4326  if((Next.CallingOnSet) && (Next.SigAspect != TTrackElement::GroundSignal))
4327  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
4328  {
4329  if(Next.SpeedTag == 68)
4330  {
4331  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm68CallingOn);
4332  }
4333  if(Next.SpeedTag == 69)
4334  {
4335  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm69CallingOn);
4336  }
4337  if(Next.SpeedTag == 70)
4338  {
4339  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm70CallingOn);
4340  }
4341  if(Next.SpeedTag == 71)
4342  {
4343  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm71CallingOn);
4344  }
4345  if(Next.SpeedTag == 72)
4346  {
4347  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm72CallingOn);
4348  }
4349  if(Next.SpeedTag == 73)
4350  {
4351  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm73CallingOn);
4352  }
4353  if(Next.SpeedTag == 74)
4354  {
4355  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm74CallingOn);
4356  }
4357  if(Next.SpeedTag == 75)
4358  {
4359  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, RailGraphics->bm75CallingOn);
4360  }
4361  }
4362  else if((Next.CallingOnSet) && (Next.SigAspect == TTrackElement::GroundSignal)) // ground signal calling on, use normal proceed aspect
4363  {
4364  for(int x = 0; x < 40; x++)
4365  {
4366  if((SigTableGroundSignal[x].SpeedTag == Next.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
4367  {
4368  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
4369  Display->PlotSignalBlankOnBitmap(Next.HLoc - GetHLocMin(), Next.VLoc - GetVLocMin(), Next.SpeedTag, Bitmap,
4370  Utilities->RHSignalFlag); // in case existing signal is a double yellow
4371  // plot special signal platform if present
4372  Graphics::TBitmap* SignalPlatformGraphic;
4373  if(PlatformOnSignalSide(4, Next.HLoc, Next.VLoc, Next.SpeedTag, SignalPlatformGraphic))
4374  {
4375  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SignalPlatformGraphic);
4376  }
4377  // now plot signal
4378  Bitmap->Canvas->Draw((Next.HLoc - GetHLocMin()) * 16, (Next.VLoc - GetVLocMin()) * 16, SigTableGroundSignal[x].SigPtr);
4379  break;
4380  }
4381  }
4382  }
4383  break;
4384  }
4385  }
4386  }
4387  else
4388  {
4389  Bitmap->Canvas->Draw(((Next.HLoc - GetHLocMin()) * 16), ((Next.VLoc - GetVLocMin()) * 16), Next.GraphicPtr);
4390  }
4391  }
4392  }
4393  if(OldTransparentColour != clB5G5R5)
4394  {
4395  Utilities->clTransparent = OldTransparentColour; // restore
4398  }
4399  Utilities->CallLogPop(1701);
4400 }
4401 
4402 // ---------------------------------------------------------------------------
4403 
4404 bool TTrack::FindAndHighlightAnUnsetGap(int Caller) // true if find one
4405 {
4406  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindAndHighlightAnUnsetGap");
4407  for(unsigned int x = 0; x < TrackVector.size(); x++)
4408  {
4409  if(TrackElementAt(1093, x).TrackType == GapJump)
4410  {
4411  if(TrackElementAt(1094, x).Conn[0] > -1)
4412  {
4413  continue; // to next 'x' value as this element has already been set
4414  }
4415  // here if identify a GapJump element not yet set
4416  GapPos = x;
4417  GapHLoc = TrackElementAt(1095, x).HLoc;
4418  GapVLoc = TrackElementAt(1096, x).VLoc;
4419  // highlight it
4421  Utilities->CallLogPop(469);
4422  return(true);
4423  }
4424  }
4425  Utilities->CallLogPop(470);
4426  return(false);
4427 }
4428 
4429 // ---------------------------------------------------------------------------
4430 
4431 bool TTrack::FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc) // true if find one
4432 {
4433  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindSetAndDisplayMatchingGap," + AnsiString(HLoc) + "," +
4434  AnsiString(VLoc));
4435  int Position;
4436  TTrackElement TrackElement;
4437 
4438  if(!(FindNonPlatformMatch(11, HLoc, VLoc, Position, TrackElement)))
4439  {
4440  Utilities->CallLogPop(471);
4441  return(false); // not found
4442  }
4443  if(TrackElement.TrackType != GapJump)
4444  {
4445  Utilities->CallLogPop(472);
4446  return(false); // found something but not a gap
4447  }
4448  if(Position == GapPos)
4449  {
4450  Utilities->CallLogPop(473);
4451  return(false); // selected original gap
4452  }
4453  if(TrackElementAt(1097, Position).Conn[0] != -1)
4454  {
4455  Utilities->CallLogPop(474);
4456  return(false); // already selected
4457  }
4458  TrackElementAt(1098, Position).Conn[0] = GapPos; // set Conn[0] at Position to GapPos & ConnLinkPos[0] to 0
4459  TrackElementAt(1099, Position).ConnLinkPos[0] = 0;
4460  TrackElementAt(1100, GapPos).Conn[0] = Position; // set other one similarly
4461  TrackElementAt(1101, GapPos).ConnLinkPos[0] = 0;
4462 // now highlight the selected location
4463  Display->Ellipse(0, HLoc * 16, VLoc * 16, clB0G5R0);
4464  Utilities->CallLogPop(475);
4465  return(true);
4466 }
4467 
4468 // ---------------------------------------------------------------------------
4469 
4470 bool TTrack::GapsUnset(int Caller)
4471 // returns true if there are gaps and any are unset
4472 {
4473  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GapsUnset");
4474  if(TrackVector.size() == 0)
4475  {
4476  Utilities->CallLogPop(476);
4477  return(false);
4478  }
4479  for(unsigned int x = 0; x < TrackVector.size(); x++)
4480  {
4481  if(TrackElementAt(1102, x).TrackType == GapJump)
4482  {
4483  if(TrackElementAt(1103, x).Conn[0] == -1) // unset if -1 (Gap always at position 0)
4484  {
4485  Utilities->CallLogPop(477);
4486  return(true);
4487  }
4488  else // set, but may not have matching element, or that element may not be set
4489  {
4490  if(TrackElementAt(1106, TrackElementAt(1107, x).Conn[0]).TrackType != GapJump)
4491  // check that the element pointed to by the gap link is a GapJump
4492  {
4493  ShowMessage("Error - gap connected to a non-gap. Railway file is corrupt, further use may cause a system crash");
4494  Utilities->CallLogPop(1137);
4495  return(false);
4496  }
4497 // here if gap connection is itself a GapJump
4498  if(TrackElementAt(1108, TrackElementAt(1109, x).Conn[0]).Conn[0] != (int)x)
4499  // check that the element pointed to by the gap link is a GapJump & that its gap link
4500  // points back to 'x'
4501  {
4502  Utilities->CallLogPop(478);
4503  return(true);
4504  }
4505 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4506  }
4507  } // if(TrackElementAt(, x).TrackType == GapJump)
4508 
4509  } // for x...
4510  Utilities->CallLogPop(479);
4511  return(false);
4512 }
4513 
4514 // ---------------------------------------------------------------------------
4515 
4516 bool TTrack::NoGaps(int Caller) // returns true if there are no gaps
4517 {
4518  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoGaps");
4519  for(unsigned int x = 0; x < TrackVector.size(); x++)
4520  {
4521  if(TrackElementAt(1110, x).TrackType == GapJump)
4522  {
4523  Utilities->CallLogPop(1105);
4524  return(false);
4525  }
4526  }
4527  Utilities->CallLogPop(1106);
4528  return(true);
4529 }
4530 
4531 // ---------------------------------------------------------------------------
4532 
4533 bool TTrack::NoNamedLocationElements(int Caller) // returns true if there are no NamedLocationElements (includes footcrossings)
4534 {
4535  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NoLocations");
4536  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4537  {
4538  if(InactiveTrackElementAt(137, x).FixedNamedLocationElement)
4539  {
4540  Utilities->CallLogPop(1107);
4541  return(false);
4542  }
4543  }
4544  for(unsigned int x = 0; x < TrackVector.size(); x++)
4545  {
4546  if(TrackElementAt(1111, x).FixedNamedLocationElement)
4547  {
4548  Utilities->CallLogPop(1108);
4549  return(false);
4550  }
4551  }
4552  Utilities->CallLogPop(1109);
4553  return(true);
4554 }
4555 
4556 // ---------------------------------------------------------------------------
4557 
4559 // returns true if there are unnamed NamedLocationElements (includes footcrossings)
4560 // returns false otherwise or if there are no NamedLocationElements
4561 {
4562  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationsNotNamed");
4563  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
4564  {
4565  if(InactiveTrackElementAt(138, x).FixedNamedLocationElement)
4566  {
4567  if(InactiveTrackElementAt(139, x).LocationName == "")
4568  {
4569  Utilities->CallLogPop(1110);
4570  return(true);
4571  }
4572  }
4573  }
4574  for(unsigned int x = 0; x < TrackVector.size(); x++)
4575  {
4576  if(TrackElementAt(1112, x).FixedNamedLocationElement)
4577  {
4578  if(TrackElementAt(1113, x).LocationName == "")
4579  {
4580  Utilities->CallLogPop(1111);
4581  return(true);
4582  }
4583  }
4584  }
4585  Utilities->CallLogPop(1112);
4586  return(false);
4587 }
4588 
4589 // ---------------------------------------------------------------------------
4590 
4591 void TTrack::ShowSelectedGap(int Caller, TDisplay *Disp)
4592 {
4593  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ShowSelectedGap,");
4594  Disp->Ellipse(1, GapHLoc * 16, GapVLoc * 16, clB0G0R5);
4595  Utilities->CallLogPop(480);
4596 }
4597 
4598 // ---------------------------------------------------------------------------
4599 
4601 {
4602  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAnyNonMatchingGaps");
4603  if(TrackVector.size() == 0)
4604  {
4605  Utilities->CallLogPop(481);
4606  return;
4607  }
4608  for(unsigned int x = 0; x < TrackVector.size(); x++)
4609  {
4610  if(TrackElementAt(1114, x).TrackType == GapJump)
4611  {
4612  if(TrackElementAt(1115, x).Conn[0] > -1) // set
4613  {
4614  if(TrackElementAt(1116, TrackElementAt(1117, x).Conn[0]).TrackType != GapJump)
4615  // check that the element pointed to by the gap link is a GapJump & if not clear Conns & CLks
4616  {
4617  TrackElementAt(1118, x).Conn[0] = -1;
4618  TrackElementAt(1119, x).ConnLinkPos[0] = -1;
4619  continue; // to next 'x'
4620  }
4621 // here if gap connection is itself a GapJump
4622  if(TrackElementAt(1120, TrackElementAt(1349, x).Conn[0]).Conn[0] != (int)x)
4623  // check that the element pointed to by the gap link is a GapJump & that its gap link points back to 'x'
4624  // if not clear Conns & CLks
4625  {
4626  TrackElementAt(1121, x).Conn[0] = -1;
4627  TrackElementAt(1122, x).ConnLinkPos[0] = -1;
4628  continue; // to next 'x'
4629  }
4630 // here if gap connection itself points back to 'x' so these two GapJumps match properly
4631 // hence no more action needed on these Conns & CLks
4632  }
4633  } // else //gap jump
4634 
4635  } // for x...
4636 // throw Exception("Test Exception");//test
4637  Utilities->CallLogPop(482);
4638 }
4639 
4640 // ---------------------------------------------------------------------------
4641 
4642 void TTrack::ResetSignals(int Caller)
4643 {
4644  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetSignals");
4645  for(unsigned int x = 0; x < TrackVector.size(); x++)
4646  {
4647  if(TrackElementAt(1123, x).TrackType == SignalPost)
4648  {
4649  TrackElementAt(1124, x).Attribute = 0;
4650  }
4651  }
4652  Utilities->CallLogPop(483);
4653 }
4654 
4655 // ---------------------------------------------------------------------------
4656 
4657 void TTrack::ResetPoints(int Caller)
4658 {
4659  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetPoints");
4660  for(unsigned int x = 0; x < TrackVector.size(); x++)
4661  {
4662  if(TrackElementAt(1125, x).TrackType == Points)
4663  {
4664  TrackElementAt(1126, x).Attribute = 0;
4665  }
4666  }
4667  Utilities->CallLogPop(484);
4668 }
4669 
4670 // ---------------------------------------------------------------------------
4671 
4672 bool TTrack::RepositionAndMapTrack(int Caller) // doesn't involve InactiveTrack
4673 {
4674  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RepositionAndMapTrack");
4675  if(TrackVector.empty())
4676  {
4677  TrackMap.clear();
4678  Utilities->CallLogPop(485);
4679  return(true);
4680  }
4681 // build new vector from map (map already in ascending order of locations & no erase elements in map)
4682  THVPair TrackMapKeyPair;
4683 
4684  NewVector.clear();
4685  TTrackMapIterator TrackMapPtr;
4686 
4687  if(!TrackMap.empty())
4688  {
4689  for(TrackMapPtr = TrackMap.begin(); TrackMapPtr != TrackMap.end(); TrackMapPtr++)
4690  {
4691  NewVector.push_back(TrackElementAt(6, TrackMapPtr->second));
4692  }
4693  }
4694  if(NewVector.size() != TrackMap.size())
4695  {
4696  throw Exception("Error - Map & Vector different sizes");
4697  }
4698  unsigned int NonZeroCount = 0;
4699 
4700  for(unsigned int x = 0; x < TrackVector.size(); x++)
4701  {
4702  if(TrackElementAt(1127, x).TrackType != Erase)
4703  {
4704  NonZeroCount++;
4705  }
4706  }
4707  if(NewVector.size() != NonZeroCount)
4708  {
4709  throw Exception("Error - NewVector & NonZero TrackVector different sizes");
4710  }
4712  TrackMap.clear(); // ready to rebuild map after repositioning of TrackVector elements
4713  TTrackMapEntry TrackMapEntry;
4714 
4715  for(unsigned int x = 0; x < TrackVector.size(); x++)
4716  {
4717  TrackMapKeyPair.first = TrackElementAt(1128, x).HLoc;
4718  TrackMapKeyPair.second = TrackElementAt(1129, x).VLoc;
4719  TrackMapEntry.first = TrackMapKeyPair;
4720  TrackMapEntry.second = x;
4721  if(!(TrackMap.insert(TrackMapEntry).second))
4722  {
4723  throw Exception("Error - map insertion failure, TrackVector in error");
4724  }
4725  }
4726 // All track now relocated in TrackVector, reset all Conns & CLks
4727  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4728  {
4729  for(unsigned int y = 0; y < 4; y++)
4730  {
4731  TrackElementAt(1130, x).Conn[y] = -1;
4732  TrackElementAt(1131, x).ConnLinkPos[y] = -1;
4733  }
4734  }
4735  RebuildLocationNameMultiMap(1); // to ensure all position entries correct after track vector changes
4736  CheckMapAndTrack(4); // test
4737  CheckMapAndInactiveTrack(4); // test
4738  CheckLocationNameMultiMap(8); // test
4739  if(!ResetGapsFromGapMap(1))
4740  {
4741  Utilities->CallLogPop(489);
4742  return(false);
4743  }
4744  Utilities->CallLogPop(490);
4745  return(true);
4746 }
4747 
4748 // ---------------------------------------------------------------------------
4749 
4750 void TTrack::BuildGapMapFromTrackVector(int Caller) // Map contains one entry for each pair of matched gaps
4751 {
4752  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BuildGapMapFromTrackVector");
4753  GapMap.clear();
4754  THVPair GapMapKeyPair, GapMapValuePair;
4755  TGapMapEntry GapMapEntry;
4756 
4757  for(unsigned int x = 0; x < TrackVector.size(); x++)
4758  {
4759  if(TrackElementAt(1132, x).TrackType == GapJump)
4760  {
4761  GapMapKeyPair.first = TrackElementAt(1133, x).HLoc;
4762  GapMapKeyPair.second = TrackElementAt(1134, x).VLoc;
4763  GapMapEntry.first = GapMapKeyPair;
4764  if(TrackElementAt(1135, x).Conn[0] == -1)
4765  {
4766  throw Exception("Error - Gap connection == -1 Can't build GapMap");
4767  }
4768  GapMapValuePair.first = TrackElementAt(7, TrackElementAt(1136, x).Conn[0]).HLoc;
4769  GapMapValuePair.second = TrackElementAt(8, TrackElementAt(1137, x).Conn[0]).VLoc;
4770  GapMapEntry.second = GapMapValuePair;
4771  if(GapMap.find(GapMapValuePair) == GapMap.end()) // if ValuePair already included as a key then result won't be end()
4772  {
4773  GapMap.insert(GapMapEntry);
4774  }
4775  }
4776  }
4777  Utilities->CallLogPop(492);
4778 }
4779 
4780 // ---------------------------------------------------------------------------
4781 
4782 bool TTrack::LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
4783 {
4784  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrack," + AnsiString((short)FinalCall));
4785  LocError = false;
4786  bool CheckForLinks = false;
4787 
4788  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
4789  {
4790  if(TrackElementAt(1138, x).TrackType == Erase) //Erase isn't used any more as a track type
4791  {
4792  continue; // skip blank elements
4793  }
4794 // check footcrossing linkages
4795  if(TrackElementAt(1139, x).TrackType == FootCrossing)
4796  {
4797  if(!CheckFootCrossingLinks(1, TrackElementAt(1140, x)))
4798  {
4799  ShowMessage(
4800  "Footbridge or underpass connection error. Each end must connect to a platform, concourse "
4801  "or other footbridge or underpass, and they can't connect to each other (i.e. a footbridge "
4802  "can't connect to an underpass or vice versa)");
4803  HLoc = TrackElementAt(1141, x).HLoc;
4804  VLoc = TrackElementAt(1142, x).VLoc;
4805  LocError = true;
4806  Utilities->CallLogPop(493);
4807  return(false);
4808  }
4809  }
4810  for(unsigned int y = 0; y < 4; y++) // check all links for each element
4811  {
4812  CheckForLinks = false;
4813  if(TrackElementAt(1143, x).Link[y] <= 0)
4814  {
4815  continue; // no link
4816  }
4817  if((TrackElementAt(1144, x).TrackType == Buffers) && (TrackElementAt(1145, x).Config[y] == End))
4818  {
4819  continue; // buffer
4820  }
4821  if(TrackElementAt(1146, x).Config[y] == Gap)
4822  {
4823  continue; // gaps set later from GapMap
4824 
4825  }
4826  // get required H & V for track element joining link 'y'
4827  int NewHLoc = TrackElementAt(1147, x).HLoc + LinkHVArray[TrackElementAt(1148, x).Link[y]][0];
4828  int NewVLoc = TrackElementAt(1149, x).VLoc + LinkHVArray[TrackElementAt(1150, x).Link[y]][1];
4829  // find track element if present
4830  bool ConnectionFoundFlag;
4831  int VecPos = GetVectorPositionFromTrackMap(14, NewHLoc, NewVLoc, ConnectionFoundFlag);
4832  if((TrackElementAt(1151, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
4833  {
4834  ShowMessage("Can't have a track element adjacent to a continuation exit");
4835  HLoc = TrackElementAt(1152, x).HLoc;
4836  VLoc = TrackElementAt(1153, x).VLoc;
4837  LocError = true;
4838  if(FinalCall)
4839  {
4840  throw Exception("Error in final track linkage - continuation adjacent to another element");
4841  }
4842  Utilities->CallLogPop(1539);
4843  return(false);
4844  }
4845  if((TrackElementAt(1154, x).TrackType == Continuation) && (TrackElementAt(1155, x).Config[y] == End))
4846  {
4847  continue;
4848  }
4849  if(ConnectionFoundFlag)
4850  {
4851  TrackElementAt(1156, x).Conn[y] = VecPos;
4852  // find connecting link in the newly found track element if there is one & make buffer & adjacent signals check
4853  bool LinkFoundFlag = false;
4854  if((TrackElementAt(1157, x).Config[1 - y] == Signal) && IsLCAtHV(50, TrackElementAt(1158, VecPos).HLoc, TrackElementAt(1350, VecPos).VLoc))
4855  {
4856  // new in v2.4.0 - Krizar (Kristian Zarebski) found this error
4857  ShowMessage("Can't have an exit signal next to a level crossing - it can cause the train to foul the crossing in some circumstances");
4858  // otherwise when single route element removed in front of train the LC will start to close and the train will crash
4859  }
4860  else if(((TrackElementAt(1159, x).TrackType == Points) || (TrackElementAt(1160, x).TrackType == SignalPost) || (TrackElementAt(1161, x).TrackType == Crossover))
4861  && (TrackElementAt(1162, VecPos).TrackType == Buffers))
4862  {
4863  ShowMessage("Can't have points, crossover or signal next to buffers - need room for a train without fouling");
4864  // need room for a train (2 elements) without fouling points or signals
4865  }
4866  else if(((TrackElementAt(1163, x).TrackType == Points) || (TrackElementAt(1164, x).TrackType == SignalPost) || (TrackElementAt(1165, x).TrackType == Crossover) ||
4867  (TrackElementAt(1166, x).TrackType == Bridge)) && (TrackElementAt(1167, VecPos).TrackType == Continuation))
4868  {
4869  ShowMessage("Can't have points, crossover, bridge or signal next to a continuation - it can cause route setting problems");
4870  // route setting won't allow an end of route selection adjacent to an existing route, which would happen
4871  // if continuation next to a signal; also none of these can be a named location, and a continuation can
4872  // be named but needs the adjacent element named too
4873  }
4874  else if((TrackElementAt(1168, x).TrackType == SignalPost) && (TrackElementAt(1169, VecPos).TrackType == SignalPost) &&
4875  (TrackElementAt(1170, x).SpeedTag == TrackElementAt(1171, VecPos).SpeedTag))
4876  {
4877  ShowMessage("Can't have two same-direction signals adjacent to each other as there is no room for a train between them");
4878  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4879  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4880  }
4881  else if((TrackElementAt(1172, x).Config[y] == Signal) && (TrackElementAt(1173, VecPos).TrackType == Bridge) && !OverrideAndHideSignalBridgeMessage)
4882  {
4883  ShowMessage("Signal facing a bridge - routes can't be truncated to this or other such signals.\n\nThis restriction can be removed or reinstated by pressing\nCTRL ALT 5. When removed this message will not be shown again.");
4884  // can't join a route to an existing route where the second signal is in an existing route and the first signal is
4885  // selected - appears as trying to select a signal that is not the next in line from the starting signal
4886  }
4887  else if(IsLCAtHV(45, TrackElementAt(1174, x).HLoc, TrackElementAt(1175, x).VLoc) && IsLCAtHV(46, TrackElementAt(1176, VecPos).HLoc, TrackElementAt(1177, VecPos).VLoc))
4888  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
4889  {
4890  ShowMessage("Can't have two level crossings adjacent to each other on the same track");
4891  }
4892  else
4893  {
4894  CheckForLinks = true;
4895  }
4896  if(CheckForLinks)
4897  {
4898  for(unsigned int a = 0; a < 4; a++)
4899  {
4900  if((TrackElementAt(1178, VecPos).Link[a] == (10 - TrackElementAt(1179, x).Link[y])) && (TrackElementAt(1180, VecPos).Config[a] != End) &&
4901  (TrackElementAt(1181, VecPos).Config[a] != Gap))
4902  {
4903  TrackElementAt(1182, x).ConnLinkPos[y] = a;
4904  // note - this ensures that if the connecting element is a leading point
4905  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
4906  // (Points have the same link value for both [0] and [2])
4907  LinkFoundFlag = true;
4908  break; // stop after first find or will find later link for leading point
4909  }
4910  }
4911  }
4912  // if there isn't a corresponding link, or buffer check fails, set the invert values for the offending element
4913  if(!LinkFoundFlag)
4914  {
4915  HLoc = TrackElementAt(1183, x).HLoc;
4916  VLoc = TrackElementAt(1184, x).VLoc;
4917  LocError = true;
4918  if(FinalCall)
4919  {
4920  throw Exception("Error in final track linkage - invalid link");
4921  }
4922  Utilities->CallLogPop(494);
4923  return(false);
4924  }
4925  }
4926  // if there isn't a connection set the invert values for the offending element
4927  else // if(ConnectionFoundFlag)
4928  {
4929  HLoc = TrackElementAt(1185, x).HLoc;
4930  VLoc = TrackElementAt(1186, x).VLoc;
4931  LocError = true;
4932  if(FinalCall)
4933  {
4934  throw Exception("Error in final track linkage - connection not found");
4935  }
4936  Utilities->CallLogPop(495);
4937  return(false);
4938  }
4939  }
4940  } // for(unsigned int x=0;x<TrackVector.size();x++)
4941 
4942  if(FinalCall)
4943  {
4945  }
4946 // final check
4947  bool ConnErrorFlag = false;
4948 
4949  for(unsigned int x = 0; x < TrackVector.size(); x++)
4950  {
4951  if((TrackElementAt(1187, x).Link[0] > 0) && (TrackElementAt(1188, x).Config[0] != End) && (TrackElementAt(1189, x).Conn[0] == -1))
4952  {
4953  ConnErrorFlag = true;
4954  }
4955  if((TrackElementAt(1190, x).Link[1] > 0) && (TrackElementAt(1191, x).Config[1] != End) && (TrackElementAt(1192, x).Conn[1] == -1))
4956  {
4957  ConnErrorFlag = true;
4958  }
4959  if((TrackElementAt(1193, x).Link[2] > 0) && (TrackElementAt(1194, x).Config[2] != End) && (TrackElementAt(1195, x).Conn[2] == -1))
4960  {
4961  ConnErrorFlag = true;
4962  }
4963  if((TrackElementAt(1196, x).Link[3] > 0) && (TrackElementAt(1197, x).Config[3] != End) && (TrackElementAt(1198, x).Conn[3] == -1))
4964  {
4965  ConnErrorFlag = true;
4966  }
4967  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
4968  {
4969  if(TrackElementAt(1199, x).ActiveTrackElementName == "")
4970  {
4971  if((TrackElementAt(1200, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1201, x).StationEntryStopLinkPos2 != -1))
4972  {
4973  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
4974  }
4975  }
4976  }
4977  }
4978  if(ConnErrorFlag)
4979  {
4980  if(FinalCall)
4981  {
4982  throw Exception("ConnError in LinkTrack - Final");
4983  }
4984  else
4985  {
4986  throw Exception("ConnError in LinkTrack - Precheck");
4987  }
4988  }
4989  bool CLkErrorFlag = false;
4990 
4991  for(unsigned int x = 0; x < TrackVector.size(); x++)
4992  {
4993  if((TrackElementAt(1202, x).Link[0] > 0) && (TrackElementAt(1203, x).Config[0] != End) && (TrackElementAt(1204, x).ConnLinkPos[0] == -1))
4994  {
4995  CLkErrorFlag = true;
4996  }
4997  if((TrackElementAt(1205, x).Link[1] > 0) && (TrackElementAt(1206, x).Config[1] != End) && (TrackElementAt(1207, x).ConnLinkPos[1] == -1))
4998  {
4999  CLkErrorFlag = true;
5000  }
5001  if((TrackElementAt(1208, x).Link[2] > 0) && (TrackElementAt(1209, x).Config[2] != End) && (TrackElementAt(1210, x).ConnLinkPos[2] == -1))
5002  {
5003  CLkErrorFlag = true;
5004  }
5005  if((TrackElementAt(1211, x).Link[3] > 0) && (TrackElementAt(1212, x).Config[3] != End) && (TrackElementAt(1213, x).ConnLinkPos[3] == -1))
5006  {
5007  CLkErrorFlag = true;
5008  }
5009  }
5010 
5011  if(CLkErrorFlag)
5012  {
5013  if(FinalCall)
5014  {
5015  throw Exception("CLkError in LinkTrack - Final");
5016  }
5017  else
5018  {
5019  throw Exception("CLkError in LinkTrack - Precheck");
5020  }
5021  }
5022 // set element lengths to min of 20m
5023  for(unsigned int x = 0; x < TrackVector.size(); x++)
5024  {
5025  if(TrackElementAt(1214, x).TrackType == Erase)
5026  {
5027  continue; // skip blank elements
5028  }
5029  if(TrackElementAt(1215, x).Length01 < 20)
5030  {
5031  TrackElementAt(1216, x).Length01 = 20;
5032  }
5033  if((TrackElementAt(1217, x).Length23 < 20) && (TrackElementAt(1218, x).Length23 != -1))
5034  {
5035  TrackElementAt(1219, x).Length23 = 20;
5036  }
5037  }
5038 
5039  if(FinalCall) // ONLY at FinalCall, no point calling twice
5040  {
5041  CalcHLocMinEtc(3);
5042  }
5043 
5044  Utilities->CallLogPop(497);
5045  return(true);
5046 }
5047 
5048 // ---------------------------------------------------------------------------
5049 
5050 bool TTrack::LinkTrackNoMessages(int Caller, bool FinalCall)
5051 {
5052  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LinkTrackNoMessages," + AnsiString((short)FinalCall));
5053  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5054  {
5055  if(TrackElementAt(1220, x).TrackType == Erase)
5056  {
5057  continue; // skip blank elements
5058 
5059  }
5060 // check footcrossing linkages
5061  if(TrackElementAt(1221, x).TrackType == FootCrossing)
5062  {
5063  if(!CheckFootCrossingLinks(3, TrackElementAt(1222, x)))
5064  {
5065  Utilities->CallLogPop(1127);
5066  return(false);
5067  }
5068  }
5069  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5070  {
5071  if(TrackElementAt(1223, x).Link[y] <= 0)
5072  {
5073  continue; // no link
5074  }
5075  if((TrackElementAt(1224, x).TrackType == Buffers) && (TrackElementAt(1225, x).Config[y] == End))
5076  {
5077  continue; // buffer
5078  }
5079  if(TrackElementAt(1226, x).Config[y] == Gap)
5080  {
5081  continue; // gaps set later from GapMap
5082 
5083  }
5084  // get required H & V for track element joining link 'y'
5085  int NewHLoc = TrackElementAt(1227, x).HLoc + LinkHVArray[TrackElementAt(1228, x).Link[y]][0];
5086  int NewVLoc = TrackElementAt(1229, x).VLoc + LinkHVArray[TrackElementAt(1230, x).Link[y]][1];
5087  // find track element if present
5088  bool ConnectionFoundFlag;
5089  int VecPos = GetVectorPositionFromTrackMap(38, NewHLoc, NewVLoc, ConnectionFoundFlag);
5090  if((TrackElementAt(1231, x).TrackType == Continuation) && (y == 0) && ConnectionFoundFlag)
5091  {
5092  if(FinalCall)
5093  {
5094  throw Exception("Error in final track linkage - continuation adjacent to another element");
5095  }
5096  Utilities->CallLogPop(1540);
5097  return(false);
5098  }
5099  if((TrackElementAt(1232, x).TrackType == Continuation) && (TrackElementAt(1233, x).Config[y] == End))
5100  {
5101  continue;
5102  }
5103  if(ConnectionFoundFlag)
5104  {
5105  TrackElementAt(1234, x).Conn[y] = VecPos;
5106  bool LinkFoundFlag = false;
5107  // find connecting link in the newly found track element if there is one & make checks
5108  if(((TrackElementAt(1235, x).TrackType == Points) || (TrackElementAt(1236, x).TrackType == SignalPost) || (TrackElementAt(1237, x).TrackType == Crossover)) &&
5109  (TrackElementAt(1238, VecPos).TrackType == Buffers))
5110  {
5111  Utilities->CallLogPop(1541);
5112  return(false);
5113  }
5114  else if(((TrackElementAt(1239, x).TrackType == Points) || (TrackElementAt(1240, x).TrackType == SignalPost) || (TrackElementAt(1241, x).TrackType == Crossover) ||
5115  (TrackElementAt(1242, x).TrackType == Bridge)) && (TrackElementAt(1243, VecPos).TrackType == Continuation))
5116  {
5117  Utilities->CallLogPop(1542);
5118  return(false);
5119  }
5120  else if((TrackElementAt(1244, x).TrackType == SignalPost) && (TrackElementAt(1245, VecPos).TrackType == SignalPost) &&
5121  (TrackElementAt(1246, x).SpeedTag == TrackElementAt(1247, VecPos).SpeedTag))
5122  {
5123  Utilities->CallLogPop(1543);
5124  return(false);
5125  }
5126  else if(IsLCAtHV(47, TrackElementAt(1248, x).HLoc, TrackElementAt(1249, x).VLoc) && IsLCAtHV(48, TrackElementAt(1250, VecPos).HLoc, TrackElementAt(1251, VecPos).VLoc))
5127  // true if a level crossing is present at both x and VecPos - can't have two adjacent level crossings on the same track
5128  {
5129  Utilities->CallLogPop(1981);
5130  return(false);
5131  }
5132 /* remove this restriction now that not permitted to treat a named continuation as a location stop
5133  else if(TrackElementAt(, x).TrackType == Continuation)
5134  {
5135  int H = TrackElementAt(, x).HLoc;
5136  int V = TrackElementAt(, x).VLoc;
5137  bool FoundFlag = false;
5138  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(18, H, V, FoundFlag);
5139  if(FoundFlag)
5140  {
5141  if(InactiveTrackElementAt(93, IMPair.first).TrackType == NamedNonStationLocation)
5142  {
5143  int NewH = TrackElementAt(, (TrackElementAt(, x).Conn[1])).HLoc;
5144  int NewV = TrackElementAt(, (TrackElementAt(, x).Conn[1])).VLoc;
5145  TIMPair NewIMPair = GetVectorPositionsFromInactiveTrackMap(19, NewH, NewV, FoundFlag);
5146  if(FoundFlag)
5147  {
5148  if(InactiveTrackElementAt(94, NewIMPair.first).TrackType != NamedNonStationLocation)
5149  {
5150  Utilities->CallLogPop();
5151  return false;
5152  }
5153  }
5154  else
5155  {
5156  Utilities->CallLogPop();
5157  return false;
5158  }
5159  }
5160  }
5161  }
5162 */
5163  for(unsigned int a = 0; a < 4; a++)
5164  {
5165  if((TrackElementAt(1252, VecPos).Link[a] == (10 - TrackElementAt(1253, x).Link[y])) && (TrackElementAt(1254, VecPos).Config[a] != End) &&
5166  (TrackElementAt(1255, VecPos).Config[a] != Gap))
5167  {
5168  TrackElementAt(1256, x).ConnLinkPos[y] = a;
5169  // note - this ensures that if the connecting element is a leading point
5170  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5171  // (Points have the same link value for both [0] and [2])
5172  LinkFoundFlag = true;
5173  break; // stop after first find or will find later link for leading point
5174  }
5175  }
5176  if(!LinkFoundFlag)
5177  {
5178  if(FinalCall)
5179  {
5180  throw Exception("Error in final track linkage in LinkTrackNoMessages - invalid link");
5181  }
5182  Utilities->CallLogPop(1128);
5183  return(false);
5184  }
5185  }
5186  else // if(ConnectionFoundFlag)
5187  {
5188  if(FinalCall)
5189  {
5190  throw Exception("Error in final track linkage in LinkTrackNoMessages - connection not found");
5191  }
5192  Utilities->CallLogPop(1129);
5193  return(false);
5194  }
5195  }
5196  } // for(unsigned int x=0;x<TrackVector.size();x++)
5197 
5198  if(FinalCall)
5199  {
5201  }
5202 // final check
5203  bool ConnErrorFlag = false;
5204 
5205  for(unsigned int x = 0; x < TrackVector.size(); x++)
5206  {
5207  if((TrackElementAt(1257, x).Link[0] > 0) && (TrackElementAt(1258, x).Config[0] != End) && (TrackElementAt(1259, x).Conn[0] == -1))
5208  {
5209  ConnErrorFlag = true;
5210  }
5211  if((TrackElementAt(1260, x).Link[1] > 0) && (TrackElementAt(1261, x).Config[1] != End) && (TrackElementAt(1262, x).Conn[1] == -1))
5212  {
5213  ConnErrorFlag = true;
5214  }
5215  if((TrackElementAt(1263, x).Link[2] > 0) && (TrackElementAt(1264, x).Config[2] != End) && (TrackElementAt(1265, x).Conn[2] == -1))
5216  {
5217  ConnErrorFlag = true;
5218  }
5219  if((TrackElementAt(1266, x).Link[3] > 0) && (TrackElementAt(1267, x).Config[3] != End) && (TrackElementAt(1268, x).Conn[3] == -1))
5220  {
5221  ConnErrorFlag = true;
5222  }
5223  if(FinalCall) // StationStopLinks only set during FinalCall so only check at FinalCall
5224  {
5225  if(TrackElementAt(1269, x).ActiveTrackElementName == "")
5226  {
5227  if((TrackElementAt(1270, x).StationEntryStopLinkPos1 != -1) || (TrackElementAt(1271, x).StationEntryStopLinkPos2 != -1))
5228  {
5229  throw Exception("Error, StationEntryStopLinkPos not -1 for unnamed element at TrackVectorPosition = " + AnsiString(x));
5230  }
5231  }
5232  }
5233  }
5234  if(ConnErrorFlag)
5235  {
5236  if(FinalCall)
5237  {
5238  throw Exception("ConnError in LinkTrack - Final");
5239  }
5240  else
5241  {
5242  throw Exception("ConnError in LinkTrack - Precheck");
5243  }
5244  }
5245  bool CLkErrorFlag = false;
5246 
5247  for(unsigned int x = 0; x < TrackVector.size(); x++)
5248  {
5249  if((TrackElementAt(1272, x).Link[0] > 0) && (TrackElementAt(1273, x).Config[0] != End) && (TrackElementAt(1274, x).ConnLinkPos[0] == -1))
5250  {
5251  CLkErrorFlag = true;
5252  }
5253  if((TrackElementAt(1275, x).Link[1] > 0) && (TrackElementAt(1276, x).Config[1] != End) && (TrackElementAt(1277, x).ConnLinkPos[1] == -1))
5254  {
5255  CLkErrorFlag = true;
5256  }
5257  if((TrackElementAt(1278, x).Link[2] > 0) && (TrackElementAt(1279, x).Config[2] != End) && (TrackElementAt(1280, x).ConnLinkPos[2] == -1))
5258  {
5259  CLkErrorFlag = true;
5260  }
5261  if((TrackElementAt(1281, x).Link[3] > 0) && (TrackElementAt(1282, x).Config[3] != End) && (TrackElementAt(1283, x).ConnLinkPos[3] == -1))
5262  {
5263  CLkErrorFlag = true;
5264  }
5265  }
5266 
5267  if(CLkErrorFlag)
5268  {
5269  if(FinalCall)
5270  {
5271  throw Exception("CLkError in LinkTrack - Final");
5272  }
5273  else
5274  {
5275  throw Exception("CLkError in LinkTrack - Precheck");
5276  }
5277  }
5278 // set element lengths to min of 20m
5279  for(unsigned int x = 0; x < TrackVector.size(); x++)
5280  {
5281  if(TrackElementAt(1284, x).TrackType == Erase)
5282  {
5283  continue; // skip blank elements
5284  }
5285  if(TrackElementAt(1285, x).Length01 < 20)
5286  {
5287  TrackElementAt(1286, x).Length01 = 20;
5288  }
5289  if((TrackElementAt(1287, x).Length23 < 20) && (TrackElementAt(1288, x).Length23 != -1))
5290  {
5291  TrackElementAt(1289, x).Length23 = 20;
5292  }
5293  }
5294 
5295  if(FinalCall) // ONLY at FinalCall, no point calling twice
5296  {
5297  CalcHLocMinEtc(7);
5298  }
5299  Utilities->CallLogPop(1130);
5300  return(true);
5301 }
5302 
5303 // ---------------------------------------------------------------------------
5304 
5305 bool TTrack::IsTrackLinked(int Caller) // not used any more
5306 {
5307  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsTrackLinked");
5308  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
5309  {
5310  if(TrackElementAt(1290, x).TrackType == Erase)
5311  {
5312  Utilities->CallLogPop(498);
5313  return(false);
5314  }
5315 // check foot linkages
5316  if(TrackElementAt(1291, x).TrackType == FootCrossing)
5317  {
5318  if(!CheckFootCrossingLinks(2, TrackElementAt(1292, x)))
5319  {
5320  Utilities->CallLogPop(499);
5321  return(false);
5322  }
5323  }
5324  for(unsigned int y = 0; y < 4; y++) // check all links for each element
5325  {
5326  if(TrackElementAt(1293, x).Link[y] <= 0)
5327  {
5328  continue; // no link
5329  }
5330  if(TrackElementAt(1294, x).Config[y] == End)
5331  {
5332  continue; // buffer or continuation
5333  }
5334  if(TrackElementAt(1295, x).Config[y] == Gap)
5335  {
5336  continue; // gaps set later from GapMap
5337 
5338  }
5339  // get required H & V for track element joining link 'y'
5340  int NewHLoc = TrackElementAt(1296, x).HLoc + LinkHVArray[TrackElementAt(1297, x).Link[y]][0];
5341  int NewVLoc = TrackElementAt(1298, x).VLoc + LinkHVArray[TrackElementAt(1299, x).Link[y]][1];
5342  // find track element if present
5343  bool ConnectionFoundFlag = false;
5344  int VecPos = GetVectorPositionFromTrackMap(15, NewHLoc, NewVLoc, ConnectionFoundFlag);
5345  if(ConnectionFoundFlag)
5346  {
5347  TrackElementAt(1300, x).Conn[y] = VecPos;
5348  // find connecting link in the newly found track element if there is one & make buffer check
5349  bool LinkFoundFlag = false;
5350  if(((TrackElementAt(1301, x).TrackType == Points) || (TrackElementAt(1302, x).TrackType == SignalPost) || (TrackElementAt(1303, x).TrackType == Crossover)) &&
5351  (TrackElementAt(1304, VecPos).TrackType == Buffers))
5352  {
5353  Utilities->CallLogPop(500);
5354  return(false);
5355  }
5356  else if((TrackElementAt(1305, x).TrackType == SignalPost) && (TrackElementAt(1306, VecPos).TrackType == SignalPost) &&
5357  (TrackElementAt(1307, x).SpeedTag == TrackElementAt(1308, VecPos).SpeedTag))
5358  {
5359  Utilities->CallLogPop(501);
5360  return(false);
5361  }
5362  else if((TrackElementAt(1309, x).TrackType == SignalPost) && (TrackElementAt(1310, VecPos).TrackType == Continuation))
5363  {
5364  Utilities->CallLogPop(502);
5365  return(false);
5366  }
5367  else
5368  {
5369  for(unsigned int a = 0; a < 4; a++)
5370  {
5371  if((TrackElementAt(1311, VecPos).Link[a] == (10 - TrackElementAt(1312, x).Link[y])) && (TrackElementAt(1313, VecPos).Config[a] != End) &&
5372  (TrackElementAt(1314, VecPos).Config[a] != Gap))
5373  {
5374  TrackElementAt(1315, x).ConnLinkPos[y] = a;
5375  // note - this ensures that if the connecting element is a leading point
5376  // then the ConnLinkPos value is 0 rather than 2, since 'a' starts at 0
5377  // (Points have the same link value for both [0] and [2])
5378  LinkFoundFlag = true;
5379  break; // stop after first find or will find later link for leading point
5380  }
5381  }
5382  }
5383  if(!LinkFoundFlag)
5384  {
5385  Utilities->CallLogPop(503);
5386  return(false);
5387  }
5388  }
5389  else // if(ConnectionFoundFlag)
5390  {
5391  Utilities->CallLogPop(504);
5392  return(false);
5393  }
5394  }
5395  } // for(unsigned int x=0;x<TrackVector.size();x++)
5396 
5397 // final check
5398  bool ConnErrorFlag = false;
5399 
5400  for(unsigned int x = 0; x < TrackVector.size(); x++)
5401  {
5402  if((TrackElementAt(1316, x).Link[0] > 0) && (TrackElementAt(1317, x).Config[0] != End) && (TrackElementAt(1318, x).Conn[0] == -1))
5403  {
5404  ConnErrorFlag = true;
5405  }
5406  if((TrackElementAt(1319, x).Link[1] > 0) && (TrackElementAt(1320, x).Config[1] != End) && (TrackElementAt(1321, x).Conn[1] == -1))
5407  {
5408  ConnErrorFlag = true;
5409  }
5410  if((TrackElementAt(1322, x).Link[2] > 0) && (TrackElementAt(1333, x).Config[2] != End) && (TrackElementAt(1334, x).Conn[2] == -1))
5411  {
5412  ConnErrorFlag = true;
5413  }
5414  if((TrackElementAt(1335, x).Link[3] > 0) && (TrackElementAt(1336, x).Config[3] != End) && (TrackElementAt(1337, x).Conn[3] == -1))
5415  {
5416  ConnErrorFlag = true;
5417  }
5418  }
5419  if(ConnErrorFlag)
5420  {
5421  Utilities->CallLogPop(505);
5422  return(false);
5423  }
5424  bool CLkErrorFlag = false;
5425 
5426  for(unsigned int x = 0; x < TrackVector.size(); x++)
5427  {
5428  if((TrackElementAt(1338, x).Link[0] > 0) && (TrackElementAt(1339, x).Config[0] != End) && (TrackElementAt(1340, x).ConnLinkPos[0] == -1))
5429  {
5430  CLkErrorFlag = true;
5431  }
5432  if((TrackElementAt(1341, x).Link[1] > 0) && (TrackElementAt(1342, x).Config[1] != End) && (TrackElementAt(1343, x).ConnLinkPos[1] == -1))
5433  {
5434  CLkErrorFlag = true;
5435  }
5436  if((TrackElementAt(1344, x).Link[2] > 0) && (TrackElementAt(1345, x).Config[2] != End) && (TrackElementAt(1346, x).ConnLinkPos[2] == -1))
5437  {
5438  CLkErrorFlag = true;
5439  }
5440  if((TrackElementAt(1347, x).Link[3] > 0) && (TrackElementAt(1394, x).Config[3] != End) && (TrackElementAt(1348, x).ConnLinkPos[3] == -1))
5441  {
5442  CLkErrorFlag = true;
5443  }
5444  }
5445 
5446  if(CLkErrorFlag)
5447  {
5448  Utilities->CallLogPop(506);
5449  return(false);
5450  }
5451  Utilities->CallLogPop(507);
5452  return(true);
5453 }
5454 
5455 // ---------------------------------------------------------------------------
5456 
5458 {
5459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetGapsFromGapMap");
5460  int Position1, Position2;
5461  TTrackElement TrackElement1, TrackElement2;
5462  TGapMapIterator GapMapPtr;
5463 
5464  if(!GapMap.empty())
5465  {
5466  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
5467  {
5468  int HLoc1 = GapMapPtr->first.first;
5469  int VLoc1 = GapMapPtr->first.second;
5470  int HLoc2 = GapMapPtr->second.first;
5471  int VLoc2 = GapMapPtr->second.second;
5472  if(!FindNonPlatformMatch(12, HLoc1, VLoc1, Position1, TrackElement1))
5473  {
5474  throw Exception("Failed to find H & V for gap1, GapMap in error");
5475  }
5476  if(!FindNonPlatformMatch(13, HLoc2, VLoc2, Position2, TrackElement2))
5477  {
5478  throw Exception("Failed to find H & V for gap2, GapMap in error");
5479  }
5480  if(TrackElementAt(9, Position1).TrackType != GapJump)
5481  {
5482  throw Exception("Element at Pos1 not a gap, GapMap in error");
5483  }
5484  if(TrackElementAt(10, Position2).TrackType != GapJump)
5485  {
5486  throw Exception("Element at Pos2 not a gap, GapMap in error");
5487  }
5488  TrackElementAt(11, Position1).Conn[0] = Position2;
5489  TrackElementAt(12, Position1).ConnLinkPos[0] = 0;
5490  TrackElementAt(13, Position2).Conn[0] = Position1;
5491  TrackElementAt(14, Position2).ConnLinkPos[0] = 0;
5492  }
5493  }
5494  Utilities->CallLogPop(510);
5495  return(true);
5496 }
5497 
5498 // ---------------------------------------------------------------------------
5499 
5500 void TTrack::TrackPush(int Caller, TTrackElement TrackElement)
5501 {
5502 // TIMPair MapEntry;
5503  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackPush," + AnsiString(TrackElement.HLoc) + "," +
5504  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
5505  THVPair TrackMapKeyPair, InactiveTrackMapKeyPair;
5506  TTrackMapEntry TrackMapEntry, InactiveTrackMapEntry;
5507  TLocationNameMultiMapEntry LocationNameEntry;
5508 
5509  LocationNameEntry.first = TrackElement.LocationName;
5510  if((TrackElement.TrackType == Platform) || (TrackElement.TrackType == Concourse) || (TrackElement.TrackType == Parapet) ||
5511  (TrackElement.TrackType == NamedNonStationLocation) || (TrackElement.TrackType == LevelCrossing))
5512  {
5513 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5514 // could arise when loading old railways with multiple NonStationNamedLocs
5515  bool FoundFlag = false;
5516  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(20, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5517  if(FoundFlag)
5518  {
5519  if((InactiveTrackElementAt(97, IMPair.first).SpeedTag == TrackElement.SpeedTag) || (InactiveTrackElementAt(98,
5520  IMPair.second).SpeedTag == TrackElement.SpeedTag))
5521  {
5522  Utilities->CallLogPop(1813);
5523  return;
5524  }
5525  }
5526  InactiveTrackVector.push_back(TrackElement); // no erase elements involved in InactiveTrackVector
5527  InactiveTrackMapKeyPair.first = TrackElement.HLoc;
5528  InactiveTrackMapKeyPair.second = TrackElement.VLoc;
5529  InactiveTrackMapEntry.first = InactiveTrackMapKeyPair;
5530  InactiveTrackMapEntry.second = InactiveTrackVector.size() - 1;
5531  InactiveTrack2MultiMap.insert(InactiveTrackMapEntry);
5532  if(TrackElement.FixedNamedLocationElement)
5533  {
5534  LocationNameEntry.second = InactiveTrackVector.size() - 1; // add to LocationNameMultiMap
5535  LocationNameMultiMap.insert(LocationNameEntry);
5536  }
5537  if(TrackElement.HLoc < HLocMin)
5538  {
5539  HLocMin = TrackElement.HLoc;
5540  }
5541  if(TrackElement.HLoc > HLocMax)
5542  {
5543  HLocMax = TrackElement.HLoc;
5544  }
5545  if(TrackElement.VLoc < VLocMin)
5546  {
5547  VLocMin = TrackElement.VLoc;
5548  }
5549  if(TrackElement.VLoc > VLocMax)
5550  {
5551  VLocMax = TrackElement.VLoc;
5552  }
5553  }
5554  else
5555  {
5556 // check whether a similar element already at this position and if so ignore it (had error where allowed multiple NonStationNamedLocs)
5557 // shouldn't arise but leave in as a safeguard
5558  bool FoundFlag = false;
5559  int VecPos = GetVectorPositionFromTrackMap(44, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5560  if(FoundFlag)
5561  {
5562  if(TrackElementAt(816, VecPos).SpeedTag == TrackElement.SpeedTag)
5563  {
5564  Utilities->CallLogPop(1814);
5565  return;
5566  }
5567  }
5568  TrackVector.push_back(TrackElement); // add erase elements to vector to keep linkages correct (now dispensed with)
5569  if(TrackElement.TrackType != Erase) // don't add erase elements to TrackMap (dispensed with these but keep code)
5570  {
5571  TrackMapKeyPair.first = TrackElement.HLoc;
5572  TrackMapKeyPair.second = TrackElement.VLoc;
5573  TrackMapEntry.first = TrackMapKeyPair;
5574  TrackMapEntry.second = TrackVector.size() - 1;
5575  TrackMap.insert(TrackMapEntry);
5576  if(TrackElement.FixedNamedLocationElement)
5577  {
5578  LocationNameEntry.second = -(int)(TrackVector.size()); // add to LocationNameMultiMap TrackVector.size = Required value + 1, so ...second = -1-Requ'd value
5579  LocationNameMultiMap.insert(LocationNameEntry);
5580  }
5581  if(TrackElement.HLoc < HLocMin)
5582  {
5583  HLocMin = TrackElement.HLoc; // exclude erase elements as HLoc & VLoc set to -2000000000
5584  }
5585  if(TrackElement.HLoc > HLocMax)
5586  {
5587  HLocMax = TrackElement.HLoc;
5588  }
5589  if(TrackElement.VLoc < VLocMin)
5590  {
5591  VLocMin = TrackElement.VLoc;
5592  }
5593  if(TrackElement.VLoc > VLocMax)
5594  {
5595  VLocMax = TrackElement.VLoc;
5596  }
5597  }
5598  }
5599 // CheckMapAndTrack(6);//test drop these to speed up, still checked outside this function
5600 // CheckMapAndInactiveTrack(6);//test
5601 
5602 // CheckLocationNameMultiMap(14);//test Can't test here as when loading the ActiveTrackElementName elements will be out of step
5603 // with the Platforms until layout fully loaded
5604  Utilities->CallLogPop(511);
5605 }
5606 
5607 // ---------------------------------------------------------------------------
5608 
5609 int TTrack::GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5610 {
5611  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionFromTrackMap," + AnsiString(HLoc) + "," +
5612  AnsiString(VLoc));
5613  THVPair TrackMapKeyPair;
5614 
5615  FoundFlag = false;
5616  TTrackMapIterator TrackMapPtr;
5617 
5618  TrackMapKeyPair.first = HLoc;
5619  TrackMapKeyPair.second = VLoc;
5620  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5621  if(TrackMapPtr == TrackMap.end())
5622  {
5623  Utilities->CallLogPop(512);
5624  return(-1); // nothing found
5625  }
5626  else
5627  {
5628  FoundFlag = true;
5629  Utilities->CallLogPop(513);
5630  return(TrackMapPtr->second);
5631  }
5632 }
5633 
5634 // ---------------------------------------------------------------------------
5635 
5636 TTrackElement &TTrack::GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
5637 {
5638  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5639  AnsiString(VLoc));
5640  THVPair TrackMapKeyPair;
5641  TTrackMapIterator TrackMapPtr;
5642 
5643  TrackMapKeyPair.first = HLoc;
5644  TrackMapKeyPair.second = VLoc;
5645  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5646  if(TrackMapPtr == TrackMap.end())
5647  {
5648  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5649  throw Exception(Message);
5650  }
5651  else
5652  {
5653  Utilities->CallLogPop(1943);
5654  return(TrackElementAt(871, TrackMapPtr->second));
5655  }
5656 }
5657 
5658 // ---------------------------------------------------------------------------
5659 
5660 TTrackElement &TTrack::GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector) //new at v2.9.0 for clipboard pref dirs
5661 { //modded at v2.9.2 to make Map & Vector references
5662  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackElementFromAnyTrackMap," + AnsiString(HLoc) + "," +
5663  AnsiString(VLoc));
5664  THVPair MapKeyPair;
5665  TTrackMapIterator MapPtr;
5666 
5667  MapKeyPair.first = HLoc;
5668  MapKeyPair.second = VLoc;
5669  MapPtr = Map.find(MapKeyPair);
5670  if(MapPtr == Map.end())
5671  {
5672  AnsiString Message = "Element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc) + " in GetTrackElementFromAnyTrackMap";
5673  throw Exception(Message);
5674  }
5675  else
5676  {
5677  Utilities->CallLogPop(2280);
5678  return(Vector.at(MapPtr->second));
5679  }
5680 }
5681 
5682 // ---------------------------------------------------------------------------
5683 
5685 {
5686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetInactiveTrackElementFromTrackMap," + AnsiString(HLoc) + "," +
5687  AnsiString(VLoc));
5688  THVPair InactiveTrackMapKeyPair;
5689  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5690 
5691  InactiveTrackMapKeyPair.first = HLoc;
5692  InactiveTrackMapKeyPair.second = VLoc;
5693  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5694  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5695  {
5696  AnsiString Message = "Inactive element not found at HLoc " + AnsiString(HLoc) + " and VLoc " + AnsiString(VLoc);
5697  throw Exception(Message);
5698  }
5699  else
5700  {
5701  Utilities->CallLogPop(1949);
5702  return(InactiveTrackElementAt(34, InactiveTrackMapPtr->second));
5703  }
5704 }
5705 
5706 // ---------------------------------------------------------------------------
5707 
5708 bool TTrack::TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5709 {
5710  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementPresentAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
5711  bool Present = true;
5712  THVPair TrackMapKeyPair;
5713  TTrackMapIterator TrackMapPtr;
5714 
5715  TrackMapKeyPair.first = HLoc;
5716  TrackMapKeyPair.second = VLoc;
5717  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
5718  if(TrackMapPtr == TrackMap.end())
5719  {
5720  Present = false;
5721  }
5722  Utilities->CallLogPop(2057);
5723  return(Present);
5724 }
5725 
5726 // ---------------------------------------------------------------------------
5727 
5728 bool TTrack::InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
5729 {
5730  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementPresentAtHV," + AnsiString(HLoc) + "," +
5731  AnsiString(VLoc));
5732  bool Present = true;
5733  THVPair InactiveTrackMapKeyPair;
5734  TInactiveTrack2MultiMapIterator InactiveTrackMapPtr;
5735 
5736  InactiveTrackMapKeyPair.first = HLoc;
5737  InactiveTrackMapKeyPair.second = VLoc;
5738  InactiveTrackMapPtr = InactiveTrack2MultiMap.find(InactiveTrackMapKeyPair); // not interested in platforms so only need to find one
5739  if(InactiveTrackMapPtr == InactiveTrack2MultiMap.end())
5740  {
5741  Present = false;
5742  }
5743  Utilities->CallLogPop(2058);
5744  return(Present);
5745 }
5746 
5747 // ---------------------------------------------------------------------------
5748 
5749 TTrack::TIMPair TTrack::GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
5750 // max number of elements is 2, for platforms
5751 // note that both elements of RetPair may be the same, if only one present in map
5752 {
5753  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromInactiveTrackMap," + AnsiString(HLoc) + "," +
5754  AnsiString(VLoc));
5755  THVPair InactiveTrackMapKeyPair;
5756  TIMPair RetPair;
5757  TInactiveTrackRange InactiveTrackRange;
5758 
5759  FoundFlag = false;
5760  InactiveTrackMapKeyPair.first = HLoc;
5761  InactiveTrackMapKeyPair.second = VLoc;
5762  if(InactiveTrack2MultiMap.empty())
5763  {
5764  RetPair.first = 0;
5765  RetPair.second = 0;
5766  Utilities->CallLogPop(1815);
5767  return(RetPair); // map empty
5768  }
5769  InactiveTrackRange = InactiveTrack2MultiMap.equal_range(InactiveTrackMapKeyPair);
5770  if(InactiveTrackRange.first == InactiveTrackRange.second)
5771  {
5772  RetPair.first = 0;
5773  RetPair.second = 0;
5774  Utilities->CallLogPop(514);
5775  return(RetPair); // nothing found
5776  }
5777  else
5778  {
5779  RetPair.first = InactiveTrackRange.first->second;
5780  RetPair.second = (--InactiveTrackRange.second)->second;
5781  FoundFlag = true;
5782  Utilities->CallLogPop(515);
5783  return(RetPair);
5784  }
5785 }
5786 
5787 // ---------------------------------------------------------------------------
5788 
5789 bool TTrack::MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
5790 {
5791 // only change where have adjacent points with their diverging links connected - not appropriate for non-straight points
5792  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MatchingPoint," + AnsiString(TrackVectorPosition) + "," +
5793  AnsiString(DivergingPosition));
5794  TTrackElement T1 = TrackElementAt(15, TrackVectorPosition);
5795  TTrackElement T2 = TrackElementAt(16, DivergingPosition);
5796  int SpeedTag1 = T1.SpeedTag;
5797  int SpeedTag2 = T2.SpeedTag;
5798 
5799  if(T1.Attribute != T2.Attribute)
5800  {
5801  Utilities->CallLogPop(516);
5802  return(false);
5803  }
5804  if(((SpeedTag1 == 7) && (SpeedTag2 == 10)) || // straight track hor, diverging track vert
5805  ((SpeedTag1 == 10) && (SpeedTag2 == 7)) || ((SpeedTag1 == 8) && (SpeedTag2 == 9)) || ((SpeedTag1 == 9) && (SpeedTag2 == 8)) ||
5806  ((SpeedTag1 == 11) && (SpeedTag2 == 14)) || // straight track vert, diverging track hor
5807  ((SpeedTag1 == 14) && (SpeedTag2 == 11)) || ((SpeedTag1 == 12) && (SpeedTag2 == 13)) || ((SpeedTag1 == 13) && (SpeedTag2 == 12)) ||
5808  ((SpeedTag1 == 28) && (SpeedTag2 == 31)) || // straight track hor, diverging track 45 deg
5809  ((SpeedTag1 == 31) && (SpeedTag2 == 28)) || ((SpeedTag1 == 29) && (SpeedTag2 == 30)) || ((SpeedTag1 == 30) && (SpeedTag2 == 29)) ||
5810  ((SpeedTag1 == 32) && (SpeedTag2 == 35)) || // straight track vert, diverging track 45 deg
5811  ((SpeedTag1 == 35) && (SpeedTag2 == 32)) || ((SpeedTag1 == 33) && (SpeedTag2 == 34)) || ((SpeedTag1 == 34) && (SpeedTag2 == 33)) ||
5812  ((SpeedTag1 == 36) && (SpeedTag2 == 39)) || // straight track 45 deg, diverging track vert
5813  ((SpeedTag1 == 39) && (SpeedTag2 == 36)) || ((SpeedTag1 == 37) && (SpeedTag2 == 38)) || ((SpeedTag1 == 38) && (SpeedTag2 == 37)) ||
5814  ((SpeedTag1 == 40) && (SpeedTag2 == 43)) || // straight track 45 deg, diverging track hor
5815  ((SpeedTag1 == 43) && (SpeedTag2 == 40)) || ((SpeedTag1 == 41) && (SpeedTag2 == 42)) || ((SpeedTag1 == 42) && (SpeedTag2 == 41)))
5816  {
5817  Utilities->CallLogPop(517);
5818  return(true);
5819  }
5820  else
5821  {
5822  Utilities->CallLogPop(518);
5823  return(false);
5824  }
5825 }
5826 
5827 // ---------------------------------------------------------------------------
5828 
5829 /*
5830  bool TMapComp::operator() (const THVPair& lower, const THVPair& higher) const///HLoc VLoc
5831  {
5832  if(lower.second < higher.second) return true;
5833  else if(lower.second > higher.second) return false;
5834  else if(lower.second == higher.second)
5835  {
5836  if(lower.first < higher.first) return true;
5837  }
5838  return false;
5839  }
5840 */
5841 // ---------------------------------------------------------------------------
5842 
5843 void TTrack::PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5844 // no need to check corresponding gap, if that not set correctly it will be picked up in GapsUnset()
5845 {
5846  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotGap," + TrackElement.LogTrack(1));
5847  if(TrackElement.TrackType != GapJump)
5848  {
5849  throw Exception("Error, Wrong track type in PlotGap");
5850  }
5851  if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] > -1))
5852  {
5853  Disp->PlotOutput(39, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88set);
5854  }
5855  else if((TrackElement.SpeedTag == 88) && (TrackElement.Conn[0] == -1))
5856  {
5857  Disp->PlotOutput(40, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl88unset);
5858  }
5859  if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] > -1))
5860  {
5861  Disp->PlotOutput(41, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89set);
5862  }
5863  else if((TrackElement.SpeedTag == 89) && (TrackElement.Conn[0] == -1))
5864  {
5865  Disp->PlotOutput(42, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl89unset);
5866  }
5867  if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] > -1))
5868  {
5869  Disp->PlotOutput(43, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90set);
5870  }
5871  else if((TrackElement.SpeedTag == 90) && (TrackElement.Conn[0] == -1))
5872  {
5873  Disp->PlotOutput(44, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl90unset);
5874  }
5875  if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] > -1))
5876  {
5877  Disp->PlotOutput(45, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91set);
5878  }
5879  else if((TrackElement.SpeedTag == 91) && (TrackElement.Conn[0] == -1))
5880  {
5881  Disp->PlotOutput(46, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl91unset);
5882  }
5883  if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] > -1))
5884  {
5885  Disp->PlotOutput(47, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92set);
5886  }
5887  else if((TrackElement.SpeedTag == 92) && (TrackElement.Conn[0] == -1))
5888  {
5889  Disp->PlotOutput(48, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl92unset);
5890  }
5891  if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] > -1))
5892  {
5893  Disp->PlotOutput(49, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93set);
5894  }
5895  else if((TrackElement.SpeedTag == 93) && (TrackElement.Conn[0] == -1))
5896  {
5897  Disp->PlotOutput(50, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm93unset);
5898  }
5899  if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] > -1))
5900  {
5901  Disp->PlotOutput(51, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94set);
5902  }
5903  else if((TrackElement.SpeedTag == 94) && (TrackElement.Conn[0] == -1))
5904  {
5905  Disp->PlotOutput(52, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->bm94unset);
5906  }
5907  if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] > -1))
5908  {
5909  Disp->PlotOutput(53, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95set);
5910  }
5911  else if((TrackElement.SpeedTag == 95) && (TrackElement.Conn[0] == -1))
5912  {
5913  Disp->PlotOutput(54, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->gl95unset);
5914  }
5915  Utilities->CallLogPop(1101);
5916 }
5917 
5918 // ---------------------------------------------------------------------------
5919 
5920 void TTrack::PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
5921 {
5922  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPoints," + TrackElement.LogTrack(2));
5923  if(TrackElement.TrackType != Points)
5924  {
5925  throw Exception("Error, Wrong track type in PlotPoints");
5926  }
5927  Disp->PlotPointBlank(0, TrackElement.HLoc, TrackElement.VLoc); // to get rid of earlier fillet
5928  TrackElement.PlotVariableTrackElement(4, Disp);
5929  if(BothFillets)
5930  {
5931  if(TrackElement.SpeedTag < 28)
5932  {
5933  Disp->PlotOutput(55, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][0]);
5934  Disp->PlotOutput(73, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][1]);
5935  }
5936  else if(TrackElement.SpeedTag < 132)
5937  {
5938  Disp->PlotOutput(56, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][0]);
5939  Disp->PlotOutput(74, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][1]);
5940  }
5941  else
5942  {
5943  Disp->PlotOutput(70, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][0]);
5944  Disp->PlotOutput(71, TrackElement.HLoc * 16, TrackElement.VLoc * 16, RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][1]);
5945  }
5946  }
5947  else
5948  {
5949  if(TrackElement.SpeedTag < 28)
5950  {
5951  Disp->PlotOutput(75, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5952  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
5953  }
5954  else if(TrackElement.SpeedTag < 132)
5955  {
5956  Disp->PlotOutput(76, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5957  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
5958  }
5959  else
5960  {
5961  Disp->PlotOutput(72, TrackElement.HLoc * 16, TrackElement.VLoc * 16,
5962  RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
5963  }
5964  }
5965 // replot platform if required
5966  TIMPair IMPair;
5967  bool FoundFlag;
5968 
5969  IMPair = GetVectorPositionsFromInactiveTrackMap(15, TrackElement.HLoc, TrackElement.VLoc, FoundFlag);
5970  if(FoundFlag)
5971  {
5972  // only one platform possible at points so only need to plot IMPair.first
5973  TTrackElement PlatElement = InactiveTrackElementAt(89, IMPair.first);
5974  PlatElement.PlotVariableTrackElement(5, Disp); // to plot as striped or non-striped depending on whether named or not
5975  }
5976  Utilities->CallLogPop(519);
5977 }
5978 
5979 // ---------------------------------------------------------------------------
5980 
5981 void TTrack::PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
5982 {
5983 // Can't use TrackElement.PlotVariableTrackElement() here as graphic changes depending on signal colour
5984  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignal," + TrackElement.LogTrack(3));
5985  if(TrackElement.TrackType != SignalPost)
5986  {
5987  throw Exception("Error, Wrong track type in PlotSignal");
5988  }
5989  for(int x = 0; x < 40; x++)
5990  {
5991  if((SigTable[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == TrackElement.Attribute))
5992  {
5993  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
5994  Disp->PlotSignalBlank(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
5995 // in case existing signal is a double yellow
5996  // plot platforms if present
5997 // Graphics::TBitmap* SignalPlatformGraphic;
5998 // if(PlatformOnSignalSide(0, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, SignalPlatformGraphic))
5999 // Above dropped at v2.3.0. Now plot either or both platforms if present regardless of which side they are on. The platforms will
6000 // be consistent with the signal graphic as can't enter an inappropriate platform. The new right hand signal option caused platforms
6001 // to not be plotted with the above function.
6002  PlotSignalPlatforms(0, TrackElement.HLoc, TrackElement.VLoc, Disp); // if no platforms nothing is plotted
6003  // now plot signal (double yellow overwrites most of signal platform if present)
6004  // additions at version 0.6 for other aspects & ground sigs
6005  if(TrackElement.SigAspect == TTrackElement::ThreeAspect)
6006  {
6007  Disp->PlotOutput(117, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableThreeAspect[x].SigPtr);
6008  }
6009  else if(TrackElement.SigAspect == TTrackElement::TwoAspect)
6010  {
6011  Disp->PlotOutput(118, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableTwoAspect[x].SigPtr);
6012  }
6013  else if(TrackElement.SigAspect == TTrackElement::GroundSignal)
6014  {
6015  Disp->PlotOutput(119, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6016  }
6017  else // 4 aspect
6018  {
6019  Disp->PlotOutput(58, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTable[x].SigPtr);
6020  }
6021  if((TrackElement.CallingOnSet) && (TrackElement.SigAspect != TTrackElement::GroundSignal))
6022  // normal signal calling on, need to add extra graphic, basic red signal plotted above from SigTable
6023  {
6024  if(TrackElement.SpeedTag == 68)
6025  {
6026  Disp->PlotOutput(59, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm68CallingOn);
6027  }
6028  if(TrackElement.SpeedTag == 69)
6029  {
6030  Disp->PlotOutput(60, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm69CallingOn);
6031  }
6032  if(TrackElement.SpeedTag == 70)
6033  {
6034  Disp->PlotOutput(61, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm70CallingOn);
6035  }
6036  if(TrackElement.SpeedTag == 71)
6037  {
6038  Disp->PlotOutput(62, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm71CallingOn);
6039  }
6040  if(TrackElement.SpeedTag == 72)
6041  {
6042  Disp->PlotOutput(63, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm72CallingOn);
6043  }
6044  if(TrackElement.SpeedTag == 73)
6045  {
6046  Disp->PlotOutput(64, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm73CallingOn);
6047  }
6048  if(TrackElement.SpeedTag == 74)
6049  {
6050  Disp->PlotOutput(65, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm74CallingOn);
6051  }
6052  if(TrackElement.SpeedTag == 75)
6053  {
6054  Disp->PlotOutput(66, (TrackElement.HLoc * 16), (TrackElement.VLoc * 16), RailGraphics->bm75CallingOn);
6055  }
6056  }
6057  else if((TrackElement.CallingOnSet) && (TrackElement.SigAspect == TTrackElement::GroundSignal))
6058  // ground signal calling on, need to use normal proceed aspect
6059  {
6060  for(int x = 0; x < 40; x++)
6061  {
6062  if((SigTableGroundSignal[x].SpeedTag == TrackElement.SpeedTag) && (SigTable[x].Attribute == 1)) // use attr 1 for proceed
6063  {
6064  // plot blank first, then plot platform if present - striped or not depending on LocationName being set
6065  Disp->PlotSignalBlank(1, TrackElement.HLoc, TrackElement.VLoc, TrackElement.SpeedTag, Utilities->RHSignalFlag);
6066  // plot special signal platform if present
6067  Graphics::TBitmap* SignalPlatformGraphic;
6068  PlotSignalPlatforms(1, TrackElement.HLoc, TrackElement.VLoc, Disp);
6069  // now plot signal
6070  Disp->PlotOutput(123, TrackElement.HLoc * 16, TrackElement.VLoc * 16, SigTableGroundSignal[x].SigPtr);
6071  }
6072  }
6073  }
6074  break;
6075  }
6076  }
6077  Utilities->CallLogPop(520);
6078 }
6079 
6080 // ---------------------------------------------------------------------------
6081 
6082 void TTrack::PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
6083 {
6084  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSignalPlatforms," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6085  bool FoundFlag;
6086  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(13, HLoc, VLoc, FoundFlag);
6087 
6088  if(!FoundFlag)
6089  {
6090  Utilities->CallLogPop(2112);
6091  return;
6092  }
6093  TTrackElement IAElement1 = InactiveTrackElementAt(124, IMPair.first);
6094  TTrackElement IAElement2 = InactiveTrackElementAt(125, IMPair.second);
6095 
6096  // don't want 'else if' for the below as may need to plot 2 platforms
6097  if((IAElement1.SpeedTag == 76) || (IAElement2.SpeedTag == 76)) // top plat
6098  {
6099  if(IAElement1.LocationName == "") // '2' will be same
6100  {
6101  Disp->PlotOutput(239, HLoc * 16, VLoc * 16, RailGraphics->gl76Striped);
6102  }
6103  else
6104  {
6105  Disp->PlotOutput(240, HLoc * 16, VLoc * 16, RailGraphics->gl76);
6106  }
6107  }
6108  if((IAElement1.SpeedTag == 77) || (IAElement2.SpeedTag == 77)) // bot plat
6109  {
6110  if(IAElement1.LocationName == "") // '2' will be same
6111  {
6112  Disp->PlotOutput(241, HLoc * 16, VLoc * 16, RailGraphics->bm77Striped);
6113  }
6114  else
6115  {
6116  Disp->PlotOutput(242, HLoc * 16, VLoc * 16, RailGraphics->bm77);
6117  }
6118  }
6119  if((IAElement1.SpeedTag == 78) || (IAElement2.SpeedTag == 78)) // lh plat
6120  {
6121  if(IAElement1.LocationName == "") // '2' will be same
6122  {
6123  Disp->PlotOutput(243, HLoc * 16, VLoc * 16, RailGraphics->bm78Striped);
6124  }
6125  else
6126  {
6127  Disp->PlotOutput(244, HLoc * 16, VLoc * 16, RailGraphics->bm78);
6128  }
6129  }
6130  if((IAElement1.SpeedTag == 79) || (IAElement2.SpeedTag == 79)) // rh plat
6131  {
6132  if(IAElement1.LocationName == "") // '2' will be same
6133  {
6134  Disp->PlotOutput(245, HLoc * 16, VLoc * 16, RailGraphics->gl79Striped);
6135  }
6136  else
6137  {
6138  Disp->PlotOutput(246, HLoc * 16, VLoc * 16, RailGraphics->gl79);
6139  }
6140  }
6141  Utilities->CallLogPop(2113);
6142 }
6143 
6144 // ---------------------------------------------------------------------------
6145 
6146 void TTrack::SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
6147 {
6148 // Set attrs to 0=closed to trains; 1=open to trains; 2 = changing = closed to trains
6149  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LowerLinkedLevelCrossingBarrierAttributes," + AnsiString(HLoc) + "," +
6150  AnsiString(VLoc));
6151 // find topmost LC, opening them all (to trains) in turn
6152  int UpStep = 0;
6153 
6154  while(IsLCAtHV(0, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6155  {
6156  SetLCAttributeAtHV(0, HLoc, (VLoc + UpStep), Attr);
6157  UpStep--;
6158  }
6159 // now find bottommost LC, opening them all (to trains) in turn
6160  int DownStep = 1;
6161 
6162  while(IsLCAtHV(1, HLoc, (VLoc + DownStep)))
6163  {
6164  SetLCAttributeAtHV(1, HLoc, (VLoc + DownStep), Attr);
6165  DownStep++;
6166  }
6167 // find leftmost LC, opening them all (to trains) in turn
6168  int LeftStep = 0;
6169 
6170  while(IsLCAtHV(2, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
6171  {
6172  SetLCAttributeAtHV(2, (HLoc + LeftStep), VLoc, Attr);
6173  LeftStep--;
6174  }
6175 // now find rightmost LC, opening them all (to trains) in turn
6176  int RightStep = 1;
6177 
6178  while(IsLCAtHV(3, (HLoc + RightStep), VLoc))
6179  {
6180  SetLCAttributeAtHV(3, (HLoc + RightStep), VLoc, Attr);
6181  RightStep++;
6182  }
6183  Utilities->CallLogPop(1915);
6184 }
6185 
6186 // ---------------------------------------------------------------------------
6187 
6188 void TTrack::SetLinkedManualLCs(int Caller, int HLoc, int VLoc) //sets TypeOfRoute to 2 for all linked LCs
6189 {
6190  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLinkedManualLCs," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6191 // work upwards setting all to manual
6192  int UpStep = -1;
6193 
6194  while(IsLCAtHV(51, HLoc, (VLoc + UpStep)))
6195  {
6196  SetBarriersDownLCToManual(0, HLoc, (VLoc + UpStep));
6197  UpStep--;
6198  }
6199 // work downwards setting all to manual
6200  int DownStep = 1;
6201 
6202  while(IsLCAtHV(52, HLoc, (VLoc + DownStep)))
6203  {
6204  SetBarriersDownLCToManual(1, HLoc, (VLoc + DownStep));
6205  DownStep++;
6206  }
6207 // work leftwards setting all to manual
6208  int LeftStep = -1;
6209 
6210  while(IsLCAtHV(53, (HLoc + LeftStep), VLoc))
6211  {
6212  SetBarriersDownLCToManual(2, (HLoc + LeftStep), VLoc);
6213  LeftStep--;
6214  }
6215 // work rightwards setting all to manual
6216  int RightStep = 1;
6217 
6218  while(IsLCAtHV(54, (HLoc + RightStep), VLoc))
6219  {
6220  SetBarriersDownLCToManual(3, (HLoc + RightStep), VLoc);
6221  RightStep++;
6222  }
6223  Utilities->CallLogPop(2242);
6224 }
6225 
6226 // ---------------------------------------------------------------------------
6227 
6228 void TTrack::SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
6229 {
6230  // Set TypeOfRoute value to 2 to indicate barriers manually closed
6231  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetBarriersDownLCToManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6232  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6233  {
6234  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc))
6235  {
6236  BarriersDownVector.at(x).TypeOfRoute = 2;
6237  break;
6238  }
6239  }
6240  Utilities->CallLogPop(2243);
6241 }
6242 
6243 // ---------------------------------------------------------------------------
6244 
6245 bool TTrack::AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6246 {
6247  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedBarrierDownVectorManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6248 // work upwards
6249  int UpStep = 0; //start with this location
6250 
6251  while(IsLCAtHV(55, HLoc, (VLoc + UpStep)))
6252  {
6253  if(IsBarrierDownVectorAtHVManual(0, HLoc, (VLoc + UpStep), BDVectorPos))
6254  {
6255  Utilities->CallLogPop(2244);
6256  return(true);
6257  }
6258  UpStep--;
6259  }
6260 // work downwards
6261  int DownStep = 1;
6262 
6263  while(IsLCAtHV(56, HLoc, (VLoc + DownStep)))
6264  {
6265  if(IsBarrierDownVectorAtHVManual(1, HLoc, (VLoc + DownStep), BDVectorPos))
6266  {
6267  Utilities->CallLogPop(2245);
6268  return(true);
6269  }
6270  DownStep++;
6271  }
6272 // work leftwards
6273  int LeftStep = -1;
6274 
6275  while(IsLCAtHV(57, (HLoc + LeftStep), VLoc))
6276  {
6277  if(IsBarrierDownVectorAtHVManual(2, (HLoc + LeftStep), VLoc, BDVectorPos))
6278  {
6279  Utilities->CallLogPop(2246);
6280  return(true);
6281  }
6282  LeftStep--;
6283  }
6284 // work rightwards
6285  int RightStep = 1;
6286 
6287  while(IsLCAtHV(58, (HLoc + RightStep), VLoc))
6288  {
6289  if(IsBarrierDownVectorAtHVManual(3, (HLoc + RightStep), VLoc, BDVectorPos))
6290  {
6291  Utilities->CallLogPop(2247);
6292  return(true);
6293  }
6294  RightStep++;
6295  }
6296  Utilities->CallLogPop(2248);
6297  return(false);
6298 }
6299 
6300 // ---------------------------------------------------------------------------
6301 
6302 bool TTrack::IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
6303 {
6304  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierDownVectorAtHVManual," + AnsiString(HLoc) + "," + AnsiString(VLoc));
6305  for(unsigned int x = 0; x < BarriersDownVector.size(); x++)
6306  {
6307  if((BarriersDownVector.at(x).HLoc == HLoc) && (BarriersDownVector.at(x).VLoc == VLoc) && (BarriersDownVector.at(x).TypeOfRoute == 2))
6308  {
6309  BDVectorPos = x;
6310  Utilities->CallLogPop(2249);
6311  return(true);
6312  }
6313  }
6314  BDVectorPos = -1;
6315  Utilities->CallLogPop(2250);
6316  return(false);
6317 }
6318 
6319 // ---------------------------------------------------------------------------
6320 
6321 void TTrack::PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
6322 // open to trains
6323 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6324 {
6325  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotLoweredLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6326  AnsiString(VLoc));
6327  if(!IsLCAtHV(4, HLoc, VLoc))
6328  {
6329  throw Exception("Error, Wrong track type in PlotAndLowerLevelCrossingBarriers");
6330  }
6331  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6332  {
6333  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndLowerLevelCrossingBarriers");
6334  }
6335 // check for adjacent LCs & if so open (to trains)
6336  if(BaseElementSpeedTag == 1) // hor track element
6337  {
6338  // find topmost LC, opening them all (to trains) in turn
6339  int UpStep = 0;
6340  while(IsLCAtHV(5, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6341  {
6342  UpStep--;
6343  }
6344  UpStep++;
6345  // now find bottommost LC, opening them all (to trains) in turn
6346  int DownStep = 1;
6347  while(IsLCAtHV(6, HLoc, (VLoc + DownStep)))
6348  {
6349  DownStep++;
6350  }
6351  DownStep--;
6352  // now plot graphics, UpStep is smallest & DownStep largest
6353  // RouteGraphic is the coloured track element, BaseGraphic is non-coloured
6354  // Only need to plot the coloured graphic for the HLoc & VLoc in the vector as that is the route that is causeing the LC to flash
6355  Graphics::TBitmap *RouteGraphic;
6356  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
6357  if(TypeOfRoute == 1)
6358  {
6359  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
6360  }
6361  else if(TypeOfRoute == 0)
6362  {
6363  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
6364  }
6365  else //manual - no route
6366  {
6367  RouteGraphic = BaseGraphic;
6368  }
6369 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6370 // LinkSigRouteGraphicsPtr[1] ver }
6371 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6372 // LinkNonSigRouteGraphicsPtr[1] ver }
6373 
6374  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6375  {
6376  Disp->PlotOutput(132, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6377  Disp->PlotOutput(133, HLoc * 16, VLoc * 16, RouteGraphic);
6378  if(!Manual)
6379  {
6380  Disp->PlotOutput(134, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6381  }
6382  else
6383  {
6384  Disp->PlotOutput(247, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6385  }
6386  }
6387  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6388  {
6389  if(UpStep == 0)
6390  {
6391  Disp->PlotOutput(135, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6392  Disp->PlotOutput(136, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6393  if(!Manual)
6394  {
6395  Disp->PlotOutput(137, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6396  }
6397  else
6398  {
6399  Disp->PlotOutput(248, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6400  }
6401  Disp->PlotOutput(138, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6402  Disp->PlotOutput(139, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6403  if(!Manual)
6404  {
6405  Disp->PlotOutput(140, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6406  }
6407  else
6408  {
6409  Disp->PlotOutput(249, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6410  }
6411  }
6412  else
6413  {
6414  Disp->PlotOutput(195, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6415  Disp->PlotOutput(196, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6416  if(!Manual)
6417  {
6418  Disp->PlotOutput(197, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6419  }
6420  else
6421  {
6422  Disp->PlotOutput(250, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6423  }
6424  Disp->PlotOutput(198, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6425  Disp->PlotOutput(199, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6426  if(!Manual)
6427  {
6428  Disp->PlotOutput(200, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6429  }
6430  else
6431  {
6432  Disp->PlotOutput(251, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6433  }
6434  }
6435  }
6436  else // at least one plain graphic
6437  {
6438  if(UpStep == 0)
6439  {
6440  Disp->PlotOutput(141, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6441  Disp->PlotOutput(142, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
6442  if(!Manual)
6443  {
6444  Disp->PlotOutput(143, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6445  }
6446  else
6447  {
6448  Disp->PlotOutput(252, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6449  }
6450  Disp->PlotOutput(144, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6451  Disp->PlotOutput(145, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6452  if(!Manual)
6453  {
6454  Disp->PlotOutput(146, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6455  }
6456  else
6457  {
6458  Disp->PlotOutput(253, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6459  }
6460  }
6461  else if(DownStep == 0)
6462  {
6463  Disp->PlotOutput(201, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6464  Disp->PlotOutput(202, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6465  if(!Manual)
6466  {
6467  Disp->PlotOutput(203, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6468  }
6469  else
6470  {
6471  Disp->PlotOutput(254, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6472  }
6473  Disp->PlotOutput(204, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6474  Disp->PlotOutput(205, HLoc * 16, (VLoc + DownStep) * 16, RouteGraphic);
6475  if(!Manual)
6476  {
6477  Disp->PlotOutput(206, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6478  }
6479  else
6480  {
6481  Disp->PlotOutput(255, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6482  }
6483  }
6484  else
6485  {
6486  Disp->PlotOutput(207, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
6487  Disp->PlotOutput(208, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
6488  if(!Manual)
6489  {
6490  Disp->PlotOutput(209, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6491  }
6492  else
6493  {
6494  Disp->PlotOutput(256, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6495  }
6496  Disp->PlotOutput(210, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
6497  Disp->PlotOutput(211, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
6498  if(!Manual)
6499  {
6500  Disp->PlotOutput(212, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6501  }
6502  else
6503  {
6504  Disp->PlotOutput(257, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6505  }
6506  }
6507  for(int x = (UpStep + 1); x < DownStep; x++)
6508  {
6509  Disp->PlotOutput(147, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6510  if(x == 0)
6511  {
6512  Disp->PlotOutput(148, HLoc * 16, (VLoc + x) * 16, RouteGraphic);
6513  }
6514  else
6515  {
6516  Disp->PlotOutput(213, HLoc * 16, (VLoc + x) * 16, BaseGraphic);
6517  }
6518  if(!Manual)
6519  {
6520  Disp->PlotOutput(149, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6521  }
6522  else
6523  {
6524  Disp->PlotOutput(258, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6525  }
6526  }
6527  }
6528  Disp->Update();
6529  Utilities->CallLogPop(1958);
6530  return;
6531  }
6532 
6533  else // ver track element
6534  {
6535  // find leftmost LC, opening them all (to trains) in turn
6536  int LStep = 0;
6537  while(IsLCAtHV(7, (HLoc + LStep), VLoc))
6538  {
6539  LStep--;
6540  }
6541  LStep++;
6542  // now find rightmost LC, opening them all (to trains) in turn
6543  int RStep = 1;
6544  while(IsLCAtHV(8, (HLoc + RStep), VLoc))
6545  {
6546  RStep++;
6547  }
6548  RStep--;
6549  // now plot graphics, LStep is smallest & RStep largest
6550  Graphics::TBitmap *RouteGraphic;
6551  Graphics::TBitmap *BaseGraphic = RailGraphics->gl2;
6552  if(TypeOfRoute == 1)
6553  {
6554  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
6555  }
6556  else if(TypeOfRoute == 0)
6557  {
6558  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
6559  }
6560  else //manual
6561  {
6562  RouteGraphic = BaseGraphic;
6563  }
6564 // LinkSigRouteGraphicsPtr[0] hor } pref dir
6565 // LinkSigRouteGraphicsPtr[1] ver }
6566 // LinkNonSigRouteGraphicsPtr[0] hor } non pref dir
6567 // LinkNonSigRouteGraphicsPtr[1] ver }
6568  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6569  {
6570  Disp->PlotOutput(150, HLoc * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6571  Disp->PlotOutput(151, HLoc * 16, VLoc * 16, RouteGraphic);
6572  if(!Manual)
6573  {
6574  Disp->PlotOutput(152, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6575  }
6576  else
6577  {
6578  Disp->PlotOutput(259, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6579  }
6580  }
6581  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6582  {
6583  if(LStep == 0)
6584  {
6585  Disp->PlotOutput(153, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6586  Disp->PlotOutput(154, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6587  if(!Manual)
6588  {
6589  Disp->PlotOutput(155, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6590  }
6591  else
6592  {
6593  Disp->PlotOutput(260, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6594  }
6595  Disp->PlotOutput(156, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6596  Disp->PlotOutput(157, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6597  if(!Manual)
6598  {
6599  Disp->PlotOutput(158, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6600  }
6601  else
6602  {
6603  Disp->PlotOutput(261, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6604  }
6605  }
6606  else
6607  {
6608  Disp->PlotOutput(214, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6609  Disp->PlotOutput(215, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6610  if(!Manual)
6611  {
6612  Disp->PlotOutput(216, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6613  }
6614  else
6615  {
6616  Disp->PlotOutput(262, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6617  }
6618  Disp->PlotOutput(217, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6619  Disp->PlotOutput(218, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6620  if(!Manual)
6621  {
6622  Disp->PlotOutput(219, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6623  }
6624  else
6625  {
6626  Disp->PlotOutput(263, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6627  }
6628  }
6629  }
6630  else // at least one plain graphic
6631  {
6632  if(LStep == 0)
6633  {
6634  Disp->PlotOutput(159, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6635  Disp->PlotOutput(160, (HLoc + LStep) * 16, VLoc * 16, RouteGraphic);
6636  if(!Manual)
6637  {
6638  Disp->PlotOutput(161, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6639  }
6640  else
6641  {
6642  Disp->PlotOutput(264, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6643  }
6644  Disp->PlotOutput(162, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6645  Disp->PlotOutput(163, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6646  if(!Manual)
6647  {
6648  Disp->PlotOutput(164, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6649  }
6650  else
6651  {
6652  Disp->PlotOutput(265, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6653  }
6654  }
6655  else if(RStep == 0)
6656  {
6657  Disp->PlotOutput(220, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6658  Disp->PlotOutput(221, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6659  if(!Manual)
6660  {
6661  Disp->PlotOutput(222, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6662  }
6663  else
6664  {
6665  Disp->PlotOutput(266, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6666  }
6667  Disp->PlotOutput(223, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6668  Disp->PlotOutput(224, (HLoc + RStep) * 16, VLoc * 16, RouteGraphic);
6669  if(!Manual)
6670  {
6671  Disp->PlotOutput(225, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6672  }
6673  else
6674  {
6675  Disp->PlotOutput(267, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6676  }
6677  }
6678  else
6679  {
6680  Disp->PlotOutput(226, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6681  Disp->PlotOutput(227, (HLoc + LStep) * 16, VLoc * 16, BaseGraphic);
6682  if(!Manual)
6683  {
6684  Disp->PlotOutput(228, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6685  }
6686  else
6687  {
6688  Disp->PlotOutput(268, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6689  }
6690  Disp->PlotOutput(229, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6691  Disp->PlotOutput(230, (HLoc + RStep) * 16, VLoc * 16, BaseGraphic);
6692  if(!Manual)
6693  {
6694  Disp->PlotOutput(231, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6695  }
6696  else
6697  {
6698  Disp->PlotOutput(269, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6699  }
6700  }
6701  for(int x = (LStep + 1); x < RStep; x++)
6702  {
6703  Disp->PlotOutput(165, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6704  if(x == 0)
6705  {
6706  Disp->PlotOutput(166, (HLoc + x) * 16, VLoc * 16, RouteGraphic);
6707  }
6708  else
6709  {
6710  Disp->PlotOutput(232, (HLoc + x) * 16, VLoc * 16, BaseGraphic);
6711  }
6712  if(!Manual)
6713  {
6714  Disp->PlotOutput(167, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6715  }
6716  else
6717  {
6718  Disp->PlotOutput(270, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6719  }
6720  }
6721  }
6722  Disp->Update();
6723  Utilities->CallLogPop(1896);
6724  return;
6725  }
6726 }
6727 
6728 // ---------------------------------------------------------------------------
6729 
6730 void TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual) // open to trains
6731 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6732 {
6733  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers," +
6734  AnsiString(HLoc) + "," + AnsiString(VLoc));
6735  if(!IsLCAtHV(29, HLoc, VLoc))
6736  {
6737  throw Exception("Error, Wrong track type in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6738  }
6739  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6740  {
6741  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers");
6742  }
6743 // check for adjacent LCs & if so open (to trains)
6744  if(BaseElementSpeedTag == 1) // hor track element
6745  {
6746  // find topmost LC, opening them all (to trains) in turn
6747  int UpStep = 0;
6748  while(IsLCAtHV(30, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6749  {
6750  UpStep--;
6751  }
6752  UpStep++;
6753  // now find bottommost LC, opening them all (to trains) in turn
6754  int DownStep = 1;
6755  while(IsLCAtHV(31, HLoc, (VLoc + DownStep)))
6756  {
6757  DownStep++;
6758  }
6759  DownStep--;
6760  // now plot graphics, UpStep is smallest & DownStep largest
6761  if(UpStep == DownStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6762  {
6763  if(!Manual)
6764  {
6765  Disp->PlotOutput(179, HLoc * 16, VLoc * 16, RailGraphics->LCBothHor);
6766  }
6767  else
6768  {
6769  Disp->PlotOutput(271, HLoc * 16, VLoc * 16, RailGraphics->LCBothHorMan);
6770  }
6771  }
6772  else if((DownStep - UpStep) == 1) // double track, no need for any plain LC graphics
6773  {
6774  if(!Manual)
6775  {
6776  Disp->PlotOutput(180, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6777  Disp->PlotOutput(181, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6778  }
6779  else
6780  {
6781  Disp->PlotOutput(272, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6782  Disp->PlotOutput(273, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6783  }
6784  }
6785  else // at least one plain graphic
6786  {
6787  if(!Manual)
6788  {
6789  Disp->PlotOutput(182, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHor);
6790  Disp->PlotOutput(183, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHor);
6791  for(int x = (UpStep + 1); x < DownStep; x++)
6792  {
6793  Disp->PlotOutput(184, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlain);
6794  }
6795  }
6796  else
6797  {
6798  Disp->PlotOutput(274, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->LCTopHorMan);
6799  Disp->PlotOutput(275, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->LCBotHorMan);
6800  for(int x = (UpStep + 1); x < DownStep; x++)
6801  {
6802  Disp->PlotOutput(276, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCPlainMan);
6803  }
6804  }
6805  }
6806  // set markers
6807  for(int x = UpStep; x <= DownStep; x++)
6808  {
6809  GetInactiveTrackElementFromTrackMap(3, HLoc, (VLoc + x)).LCPlotted = true; // plotted
6810  }
6811  Display->Update();
6812  Utilities->CallLogPop(1944);
6813  return;
6814  }
6815 
6816  else // ver track element
6817  {
6818  // find leftmost LC, opening them all (to trains) in turn
6819  int LStep = 0;
6820  while(IsLCAtHV(32, (HLoc + LStep), VLoc))
6821  {
6822  LStep--;
6823  }
6824  LStep++;
6825  // now find rightmost LC, opening them all (to trains) in turn
6826  int RStep = 1;
6827  while(IsLCAtHV(33, (HLoc + RStep), VLoc))
6828  {
6829  RStep++;
6830  }
6831  RStep--;
6832  // now plot graphics, LStep is smallest & RStep largest
6833  if(LStep == RStep) // both 0, so just a single track, plot the double graphic, but plot solid bgnd first then track to get rid of earlier graphics
6834  {
6835  if(!Manual)
6836  {
6837  Disp->PlotOutput(185, HLoc * 16, VLoc * 16, RailGraphics->LCBothVer);
6838  }
6839  else
6840  {
6841  Disp->PlotOutput(277, HLoc * 16, VLoc * 16, RailGraphics->LCBothVerMan);
6842  }
6843  }
6844  else if((RStep - LStep) == 1) // double track, no need for any plain LC graphics
6845  {
6846  if(!Manual)
6847  {
6848  Disp->PlotOutput(186, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6849  Disp->PlotOutput(187, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6850  }
6851  else
6852  {
6853  Disp->PlotOutput(278, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6854  Disp->PlotOutput(279, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6855  }
6856  }
6857  else // at least one plain graphic
6858  {
6859  if(!Manual)
6860  {
6861  Disp->PlotOutput(188, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVer);
6862  Disp->PlotOutput(189, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVer);
6863  for(int x = (LStep + 1); x < RStep; x++)
6864  {
6865  Disp->PlotOutput(190, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlain);
6866  }
6867  }
6868  else
6869  {
6870  Disp->PlotOutput(280, (HLoc + LStep) * 16, VLoc * 16, RailGraphics->LCLHSVerMan);
6871  Disp->PlotOutput(281, (HLoc + RStep) * 16, VLoc * 16, RailGraphics->LCRHSVerMan);
6872  for(int x = (LStep + 1); x < RStep; x++)
6873  {
6874  Disp->PlotOutput(282, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCPlainMan);
6875  }
6876  }
6877  }
6878  // set markers
6879  for(int x = LStep; x <= RStep; x++)
6880  {
6881  GetInactiveTrackElementFromTrackMap(4, (HLoc + x), VLoc).LCPlotted = true; // plotted
6882  }
6883  Disp->Update();
6884  Utilities->CallLogPop(1945);
6885  return;
6886  }
6887 }
6888 
6889 // ---------------------------------------------------------------------------
6890 
6891 void TTrack::PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp) // closed to trains
6892 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6893 {
6894  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotRaisedLinkedLevelCrossingBarriers," + AnsiString(HLoc) + "," +
6895  AnsiString(VLoc));
6896  if(!IsLCAtHV(9, HLoc, VLoc))
6897  {
6898  throw Exception("Error, Wrong track type in PlotAndRaiseLevelCrossingBarriers");
6899  }
6900  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6901  {
6902  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotAndRaiseLevelCrossingBarriers");
6903  }
6904 // check for adjacent LCs & if so close (to trains)
6905  if(BaseElementSpeedTag == 1) // hor track element
6906  {
6907  // find topmost LC, closing them all (to trains) in turn
6908  int UpStep = 0;
6909  while(IsLCAtHV(10, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6910  {
6911  UpStep--;
6912  }
6913  UpStep++;
6914  // now find bottommost LC, opening them all (to trains) in turn
6915  int DownStep = 1;
6916  while(IsLCAtHV(11, HLoc, (VLoc + DownStep)))
6917  {
6918  DownStep++;
6919  }
6920  DownStep--;
6921  // now plot graphics, UpStep is smallest & DownStep largest
6922  for(int x = UpStep; x < (DownStep + 1); x++)
6923  {
6924  Disp->PlotOutput(168, HLoc * 16, (VLoc + x) * 16, RailGraphics->bmSolidBgnd);
6925  Disp->PlotOutput(169, HLoc * 16, (VLoc + x) * 16, RailGraphics->gl1);
6926  Disp->PlotOutput(170, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
6927  }
6928  Disp->Update();
6929  Utilities->CallLogPop(1959);
6930  return;
6931  }
6932 
6933  else // ver track element
6934  {
6935  // find leftmost LC, closing them all (to trains) in turn
6936  int LStep = 0;
6937  while(IsLCAtHV(12, (HLoc + LStep), VLoc))
6938  {
6939  LStep--;
6940  }
6941  LStep++;
6942  // now find rightmost LC, opening them all (to trains) in turn
6943  int RStep = 1;
6944  while(IsLCAtHV(13, (HLoc + RStep), VLoc))
6945  {
6946  RStep++;
6947  }
6948  RStep--;
6949  // now plot graphics, LStep is smallest & RStep largest
6950  for(int x = LStep; x < (RStep + 1); x++)
6951  {
6952  Disp->PlotOutput(171, (HLoc + x) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
6953  Disp->PlotOutput(172, (HLoc + x) * 16, VLoc * 16, RailGraphics->gl2);
6954  Disp->PlotOutput(173, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
6955  }
6956  Disp->Update();
6957  Utilities->CallLogPop(1960);
6958  return;
6959  }
6960 }
6961 
6962 // ---------------------------------------------------------------------------
6963 
6964 void TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
6965 // closed to trains
6966 // BaseElementSpeedTag: 1 = Horizontal track, 2 = vertical track
6967 {
6968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers," +
6969  AnsiString(HLoc) + "," + AnsiString(VLoc));
6970  if(!IsLCAtHV(34, HLoc, VLoc))
6971  {
6972  throw Exception("Error, Wrong track type in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6973  }
6974  if((BaseElementSpeedTag != 1) && (BaseElementSpeedTag != 2))
6975  {
6976  throw Exception("Error, Wrong BaseElementSpeedTag value in PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers");
6977  }
6978  TTrackElement TE;
6979 
6980 // check for adjacent LCs & if so close (to trains)
6981  if(BaseElementSpeedTag == 1) // hor track element
6982  {
6983  // find topmost LC, closing them all (to trains) in turn
6984  int UpStep = 0;
6985  while(IsLCAtHV(35, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
6986  {
6987  UpStep--;
6988  }
6989  UpStep++;
6990  // now find bottommost LC, opening them all (to trains) in turn
6991  int DownStep = 1;
6992  while(IsLCAtHV(36, HLoc, (VLoc + DownStep)))
6993  {
6994  DownStep++;
6995  }
6996  DownStep--;
6997  // now plot graphics, UpStep is smallest & DownStep largest
6998  for(int x = UpStep; x <= DownStep; x++)
6999  {
7000  Disp->PlotOutput(191, HLoc * 16, (VLoc + x) * 16, RailGraphics->LCBothVer);
7001  GetInactiveTrackElementFromTrackMap(1, HLoc, (VLoc + x)).LCPlotted = true; // plotted
7002  }
7003  Display->Update();
7004  Utilities->CallLogPop(1946);
7005  return;
7006  }
7007 
7008  else // ver track element
7009  {
7010  // find leftmost LC, closing them all (to trains) in turn
7011  int LStep = 0;
7012  while(IsLCAtHV(37, (HLoc + LStep), VLoc))
7013  {
7014  LStep--;
7015  }
7016  LStep++;
7017  // now find rightmost LC, opening them all (to trains) in turn
7018  int RStep = 1;
7019  while(IsLCAtHV(38, (HLoc + RStep), VLoc))
7020  {
7021  RStep++;
7022  }
7023  RStep--;
7024  // now plot graphics, LStep is smallest & RStep largest
7025  for(int x = LStep; x <= RStep; x++)
7026  {
7027  Disp->PlotOutput(192, (HLoc + x) * 16, VLoc * 16, RailGraphics->LCBothHor);
7028  GetInactiveTrackElementFromTrackMap(2, (HLoc + x), VLoc).LCPlotted = true; // plotted
7029  }
7030  Display->Update();
7031  Utilities->CallLogPop(1947);
7032  return;
7033  }
7034 }
7035 
7036 // ---------------------------------------------------------------------------
7037 
7038 void TTrack::PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
7039 {
7040  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotBaseElementsOnly," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7041  Graphics::TBitmap *RouteGraphic;
7042  Graphics::TBitmap *BaseGraphic = RailGraphics->gl1;
7043 
7044  if(BaseElementSpeedTag == 1)
7045  {
7046  if(TypeOfRoute == 1)
7047  {
7048  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[0];
7049  }
7050  else if(TypeOfRoute == 0)
7051  {
7052  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[0];
7053  }
7054  else //manual
7055  {
7056  RouteGraphic = BaseGraphic;
7057  }
7058  if(State == Raising)
7059  {
7060  RouteGraphic = BaseGraphic;
7061  }
7062  }
7063  else
7064  {
7065  BaseGraphic = RailGraphics->gl2;
7066  if(TypeOfRoute == 1)
7067  {
7068  RouteGraphic = RailGraphics->LinkSigRouteGraphicsPtr[1];
7069  }
7070  else if(TypeOfRoute == 0)
7071  {
7072  RouteGraphic = RailGraphics->LinkNonSigRouteGraphicsPtr[1];
7073  }
7074  else
7075  {
7076  RouteGraphic = BaseGraphic; //manual
7077  }
7078  if(State == Raising)
7079  {
7080  RouteGraphic = BaseGraphic;
7081  }
7082  }
7083  int UpStep = 0;
7084 
7085  while(IsLCAtHV(14, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7086  {
7087  Disp->PlotOutput(174, HLoc * 16, (VLoc + UpStep) * 16, RailGraphics->bmSolidBgnd);
7088  if(UpStep == 0)
7089  {
7090  Disp->PlotOutput(175, HLoc * 16, (VLoc + UpStep) * 16, RouteGraphic);
7091  }
7092  else
7093  {
7094  Disp->PlotOutput(234, HLoc * 16, (VLoc + UpStep) * 16, BaseGraphic);
7095  }
7096  UpStep--;
7097  }
7098 // now find bottommost LC, opening them all (to trains) in turn
7099  int DownStep = 1;
7100 
7101  while(IsLCAtHV(15, HLoc, (VLoc + DownStep)))
7102  {
7103  Disp->PlotOutput(176, HLoc * 16, (VLoc + DownStep) * 16, RailGraphics->bmSolidBgnd);
7104  Disp->PlotOutput(177, HLoc * 16, (VLoc + DownStep) * 16, BaseGraphic);
7105  DownStep++;
7106  }
7107  int LeftStep = 0;
7108 
7109  while(IsLCAtHV(16, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7110  {
7111  Disp->PlotOutput(233, (HLoc + LeftStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7112  if(LeftStep == 0)
7113  {
7114  Disp->PlotOutput(235, (HLoc + LeftStep) * 16, VLoc * 16, RouteGraphic);
7115  }
7116  else
7117  {
7118  Disp->PlotOutput(236, (HLoc + LeftStep) * 16, VLoc * 16, BaseGraphic);
7119  }
7120  LeftStep--;
7121  }
7122 // now find rightmost LC, opening them all (to trains) in turn
7123  int RightStep = 1;
7124 
7125  while(IsLCAtHV(17, (HLoc + RightStep), VLoc))
7126  {
7127  Disp->PlotOutput(237, (HLoc + RightStep) * 16, VLoc * 16, RailGraphics->bmSolidBgnd);
7128  Disp->PlotOutput(238, (HLoc + RightStep) * 16, VLoc * 16, BaseGraphic);
7129  RightStep++;
7130  }
7131  Disp->Update();
7132  Utilities->CallLogPop(1914);
7133 }
7134 
7135 // ---------------------------------------------------------------------------
7136 
7137 bool TTrack::IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully down
7138 {
7139 // return false for no LC there, flashing or a closed (to trains) LC
7140  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCBarrierDownAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7141  bool FoundFlag;
7142  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(21, HLoc, VLoc, FoundFlag);
7143 
7144  if(!FoundFlag)
7145  {
7146  Utilities->CallLogPop(1898);
7147  return(false);
7148  }
7149  if(InactiveTrackElementAt(100, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7150  {
7151  Utilities->CallLogPop(1899);
7152  return(false);
7153  }
7154  if(InactiveTrackElementAt(103, IMPair.first).Attribute == 1)
7155  {
7156  Utilities->CallLogPop(1900);
7157  return(true);
7158  }
7159  Utilities->CallLogPop(1901);
7160  return(false);
7161 }
7162 
7163 // ---------------------------------------------------------------------------
7164 
7165 bool TTrack::IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc) // returns true only if fully up
7166 {
7167 // return false for no LC there, flashing LC or open (to trains) LC
7168  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierUpLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7169  bool FoundFlag;
7170  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(24, HLoc, VLoc, FoundFlag);
7171 
7172  if(!FoundFlag)
7173  {
7174  Utilities->CallLogPop(1922);
7175  return(false);
7176  }
7177  if(InactiveTrackElementAt(110, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7178  {
7179  Utilities->CallLogPop(1923);
7180  return(false);
7181  }
7182  if(InactiveTrackElementAt(111, IMPair.first).Attribute == 0)
7183  {
7184  Utilities->CallLogPop(1924);
7185  return(true);
7186  }
7187  Utilities->CallLogPop(1925);
7188  return(false);
7189 }
7190 
7191 // ---------------------------------------------------------------------------
7192 
7193 bool TTrack::IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
7194 {
7195 // return true for barrier in process of moving
7196  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsBarrierFlashingAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7197  bool FoundFlag;
7198  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(25, HLoc, VLoc, FoundFlag);
7199 
7200  if(!FoundFlag)
7201  {
7202  Utilities->CallLogPop(1918);
7203  return(false);
7204  }
7205  if(InactiveTrackElementAt(112, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7206  {
7207  Utilities->CallLogPop(1919);
7208  return(false);
7209  }
7210  if(InactiveTrackElementAt(113, IMPair.first).Attribute == 2)
7211  {
7212  Utilities->CallLogPop(1920);
7213  return(true);
7214  }
7215  Utilities->CallLogPop(1921);
7216  return(false);
7217 }
7218 
7219 // ---------------------------------------------------------------------------
7220 
7221 bool TTrack::IsLCAtHV(int Caller, int HLoc, int VLoc)
7222 {
7223 // return true for an LC at H&V
7224  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsLCAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc));
7225  bool FoundFlag;
7226  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(22, HLoc, VLoc, FoundFlag);
7227 
7228  if(!FoundFlag)
7229  {
7230  Utilities->CallLogPop(1902);
7231  return(false);
7232  }
7233  if(InactiveTrackElementAt(101, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7234  {
7235  Utilities->CallLogPop(1903);
7236  return(false);
7237  }
7238  Utilities->CallLogPop(1904);
7239  return(true);
7240 }
7241 
7242 // ---------------------------------------------------------------------------
7243 
7244 void TTrack::SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
7245 {
7246  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCAttributeAtHV," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7247  AnsiString(Attr));
7248  bool FoundFlag;
7249  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(23, HLoc, VLoc, FoundFlag);
7250 
7251  if(!FoundFlag)
7252  {
7253  throw Exception("Element not found in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7254  }
7255  if(InactiveTrackElementAt(102, IMPair.first).TrackType != LevelCrossing) // only need to check first as second can only be a platform
7256  {
7257  throw Exception("Element not a level crossing in LowerLCBarriersAtHV " + AnsiString(HLoc) + "," + AnsiString(VLoc));
7258  }
7259  InactiveTrackElementAt(104, IMPair.first).Attribute = Attr;
7260  Utilities->CallLogPop(1905);
7261  return;
7262 }
7263 
7264 // ---------------------------------------------------------------------------
7265 
7267 {
7268  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetLevelCrossings");
7269  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
7270  {
7271  TTrackElement InactiveTrackElement = InactiveTrackElementAt(140, x);
7272  if(InactiveTrackElement.TrackType == LevelCrossing)
7273  {
7274  InactiveTrackElementAt(141, x).Attribute = 0;
7275  // though this only resets the attributes the LC will display correctly when call Clearand.. in BaseMode
7276  }
7277  }
7278  Utilities->CallLogPop(1913);
7279  return;
7280 }
7281 
7282 // ---------------------------------------------------------------------------
7283 
7284 bool TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
7285 {
7286 // return true if there is either a route set or being set on any element or a train on any element
7287  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AnyLinkedLevelCrossingElementsWithRoutesOrTrains," + AnsiString(HLoc) +
7288  "," + AnsiString(VLoc));
7289 
7290  THVPair TrackMapKeyPair;
7291  TTrack::TTrackMapIterator TrackMapPtr;
7292  int DummyRouteNumber;
7293 
7294  TrainPresent = false;
7295 // find topmost LC, checking each for routes & trains
7296  int UpStep = 0;
7297 
7298  while(IsLCAtHV(25, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7299  {
7300  TrackMapKeyPair.first = HLoc;
7301  TrackMapKeyPair.second = VLoc + UpStep;
7302  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7303  if(AllRoutes->GetRouteTypeAndNumber(20, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7304  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7305  {
7306  Utilities->CallLogPop(1932);
7307  return(true);
7308  }
7309  if(TrackElementAt(867, TrackMapPtr->second).TrainIDOnElement != -1)
7310  {
7311  TrainPresent = true;
7312  Utilities->CallLogPop(1933);
7313  return(true);
7314  }
7315  if(LCInSearchVector(0, HLoc, (VLoc + UpStep), SearchVector)) //route being set, added at v2.8.0
7316  {
7317  Utilities->CallLogPop(2274);
7318  return(true);
7319  }
7320  UpStep--;
7321  }
7322 // now find bottommost LC, opening them all (to trains) in turn
7323  int DownStep = 1;
7324 
7325  while(IsLCAtHV(26, HLoc, (VLoc + DownStep)))
7326  {
7327  TrackMapKeyPair.first = HLoc;
7328  TrackMapKeyPair.second = VLoc + DownStep;
7329  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7330  if(AllRoutes->GetRouteTypeAndNumber(21, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7331  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7332  {
7333  Utilities->CallLogPop(1934);
7334  return(true);
7335  }
7336  if(TrackElementAt(868, TrackMapPtr->second).TrainIDOnElement != -1)
7337  {
7338  TrainPresent = true;
7339  Utilities->CallLogPop(1935);
7340  return(true);
7341  }
7342  if(LCInSearchVector(1, HLoc, (VLoc + DownStep), SearchVector)) //route being set, added at v2.8.0
7343  {
7344  Utilities->CallLogPop(2275);
7345  return(true);
7346  }
7347  DownStep++;
7348  }
7349 // find leftmost LC
7350  int LeftStep = 0;
7351 
7352  while(IsLCAtHV(27, (HLoc + LeftStep), VLoc)) // will always find LC at LeftStep == 0
7353  {
7354  TrackMapKeyPair.first = HLoc + LeftStep;
7355  TrackMapKeyPair.second = VLoc;
7356  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7357  if(AllRoutes->GetRouteTypeAndNumber(22, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7358  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7359  {
7360  Utilities->CallLogPop(1936);
7361  return(true);
7362  }
7363  if(TrackElementAt(869, TrackMapPtr->second).TrainIDOnElement != -1)
7364  {
7365  TrainPresent = true;
7366  Utilities->CallLogPop(1937);
7367  return(true);
7368  }
7369  if(LCInSearchVector(2, (HLoc + LeftStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7370  {
7371  Utilities->CallLogPop(2276);
7372  return(true);
7373  }
7374  LeftStep--;
7375  }
7376 // now find rightmost LC, opening them all (to trains) in turn
7377  int RightStep = 1;
7378 
7379  while(IsLCAtHV(28, (HLoc + RightStep), VLoc))
7380  {
7381  TrackMapKeyPair.first = HLoc + RightStep;
7382  TrackMapKeyPair.second = VLoc;
7383  TrackMapPtr = TrackMap.find(TrackMapKeyPair);
7384  if(AllRoutes->GetRouteTypeAndNumber(23, TrackMapPtr->second, 0, DummyRouteNumber) != TAllRoutes::NoRoute)
7385  // use 0 for LinkPos, only 1 track element so 0 or 1 would be OK
7386  {
7387  Utilities->CallLogPop(1938);
7388  return(true);
7389  }
7390  if(TrackElementAt(870, TrackMapPtr->second).TrainIDOnElement != -1)
7391  {
7392  TrainPresent = true;
7393  Utilities->CallLogPop(1939);
7394  return(true);
7395  }
7396  if(LCInSearchVector(3, (HLoc + RightStep), VLoc, SearchVector)) //route being set, added at v2.8.0
7397  {
7398  Utilities->CallLogPop(2277);
7399  return(true);
7400  }
7401  RightStep++;
7402  }
7403  Utilities->CallLogPop(1940);
7404  return(false);
7405 }
7406 
7407 // ---------------------------------------------------------------------------
7408 
7409 bool TTrack::LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector) //added at v2.8.0
7410 {
7411  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LCInSearchVector," + HLoc + "," + VLoc);
7412  for(unsigned int x = 0; x < SearchVector.size(); x++)
7413  {
7414  if((TrackElementAt(1019, SearchVector.at(x).GetTrackVectorPosition()).HLoc == HLoc) && (TrackElementAt(1020, SearchVector.at(x).GetTrackVectorPosition()).VLoc == VLoc))
7415  {
7416  Utilities->CallLogPop(2278);
7417  return(true);
7418  }
7419  }
7420  Utilities->CallLogPop(2279);
7421  return(false);
7422 }
7423 
7424 // ---------------------------------------------------------------------------
7425 
7426 void TTrack::PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
7427 {
7428  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallFlashingLinkedLevelCrossings," +
7429  AnsiString(HLoc) + "," + AnsiString(VLoc));
7430  if(!IsLCAtHV(60, HLoc, VLoc))
7431  {
7432  throw Exception("PlotSmallFlashingLinkedLevelCrossings");
7433  }
7434 
7435 // check for adjacent LCs
7436  // find topmost LC
7437  int UpStep = 0;
7438  while(IsLCAtHV(61, HLoc, (VLoc + UpStep))) // will always find LC at UpStep == 0
7439  {
7440  UpStep--;
7441  }
7442  UpStep++;
7443  // now find bottommost LC, opening them all (to trains) in turn
7444  int DownStep = 1;
7445  while(IsLCAtHV(62, HLoc, (VLoc + DownStep)))
7446  {
7447  DownStep++;
7448  }
7449  DownStep--;
7450  // now plot graphics, UpStep is smallest & DownStep largest
7451  for(int x = UpStep; x <= DownStep; x++)
7452  {
7453  Disp->PlotSmallOutput(24, HLoc * 4, (VLoc + x) * 4, GraphicPtr);
7454  }
7455 
7456  // find leftmost LC, closing them all (to trains) in turn
7457  int LStep = 0;
7458  while(IsLCAtHV(63, (HLoc + LStep), VLoc))
7459  {
7460  LStep--;
7461  }
7462  LStep++;
7463  // now find rightmost LC, opening them all (to trains) in turn
7464  int RStep = 1;
7465  while(IsLCAtHV(64, (HLoc + RStep), VLoc))
7466  {
7467  RStep++;
7468  }
7469  RStep--;
7470  // now plot graphics, LStep is smallest & RStep largest
7471  for(int x = LStep; x <= RStep; x++)
7472  {
7473  Disp->PlotSmallOutput(25, (HLoc + x) * 4, VLoc * 4, GraphicPtr);
7474  }
7475  Display->Update();
7476  Utilities->CallLogPop(2315);
7477  return;
7478 }
7479 
7480 // ---------------------------------------------------------------------------
7481 
7482 Graphics::TBitmap *TTrack::GetFilletGraphic(int Caller, TTrackElement TrackElement)
7483 {
7484  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFilletGraphic," + TrackElement.LogTrack(4));
7485  if(TrackElement.TrackType != Points)
7486  {
7487  throw Exception("Error, Wrong track type in GetFilletGraphic");
7488  }
7489  if(TrackElement.SpeedTag < 28)
7490  {
7491  Utilities->CallLogPop(521);
7492  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 7][TrackElement.Attribute]);
7493  }
7494  else if(TrackElement.SpeedTag < 132)
7495  {
7496  Utilities->CallLogPop(522);
7497 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7498  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 20][TrackElement.Attribute]);
7499  }
7500  else
7501  {
7502  Utilities->CallLogPop(1537);
7503  return(RailGraphics->PointModeGraphicsPtr[TrackElement.SpeedTag - 108][TrackElement.Attribute]);
7504  }
7505 }
7506 
7507 // ---------------------------------------------------------------------------
7508 
7510 {
7511  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ResetAllTrainIDElements");
7512  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
7513  {
7514  TrackElementAt(1351, x).TrainIDOnElement = -1;
7517  }
7518  Utilities->CallLogPop(1342);
7519 }
7520 
7521 // ---------------------------------------------------------------------------
7522 
7523 void TTrack::GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
7524 /*
7525  Converts the screen position to the true (without offsets) HLoc, VLoc 16 x 16 square that the screen position lies within
7526 */
7527 {
7528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackLocsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7529  AnsiString(ScreenPosV));
7530  HLoc = div(ScreenPosH, 16).quot + Display->DisplayOffsetH;
7531  VLoc = div(ScreenPosV, 16).quot + Display->DisplayOffsetV;
7532 // Utilities->CallLogPop callers 523 to 534 inc used to test pop failure
7533  Utilities->CallLogPop(535);
7534 }
7535 
7536 // ---------------------------------------------------------------------------
7537 
7538 void TTrack::GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
7539 /*
7540  Converts the screen position to the true (without offsets) position
7541 */
7542 {
7543  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTruePositionsFromScreenPos," + AnsiString(ScreenPosH) + "," +
7544  AnsiString(ScreenPosV));
7545  HPos = ScreenPosH + (Display->DisplayOffsetH * 16);
7546  VPos = ScreenPosV + (Display->DisplayOffsetV * 16);
7547  Utilities->CallLogPop(536);
7548 }
7549 
7550 // ---------------------------------------------------------------------------
7551 
7552 void TTrack::GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
7553 {
7554  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetScreenPositionsFromTruePos," + AnsiString(HPosTrue) + "," +
7555  AnsiString(VPosTrue));
7556  ScreenPosH = HPosTrue - (Display->DisplayOffsetH * 16);
7557  ScreenPosV = VPosTrue - (Display->DisplayOffsetV * 16);
7558  Utilities->CallLogPop(537);
7559 }
7560 
7561 // ---------------------------------------------------------------------------
7562 
7563 void TTrack::CheckMapAndTrack(int Caller) // test
7564 {
7565  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndTrack");
7566  int Zeroes = 0;
7567  bool FoundFlag;
7568 
7569  for(unsigned int a = 0; a < TrackVector.size(); a++)
7570  {
7571  TTrackElement CheckElement = Track->TrackElementAt(1354, a);
7572  if(CheckElement.SpeedTag == 0)
7573  {
7574  Zeroes++; // zeroed elements not saved in map
7575  }
7576  else
7577  {
7578  int MapVecPos = GetVectorPositionFromTrackMap(16, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7579  if(!FoundFlag)
7580  {
7581  throw Exception("CheckMapAndTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7582  " in TrackMap, Caller=" + (AnsiString)Caller);
7583  }
7584  if(MapVecPos != (int)a)
7585  {
7586  throw Exception("CheckMapAndTrack Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7587  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)MapVecPos + " TrackVectorPos value=" + (AnsiString)a + " Caller=" +
7588  (AnsiString)Caller);
7589  }
7590  }
7591  }
7592  if(TrackVector.size() != (TrackMap.size() + Zeroes))
7593  {
7594  throw Exception("CheckMapAndTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7595  " Caller=" + (AnsiString)Caller);
7596  }
7597  Utilities->CallLogPop(538);
7598  return;
7599 }
7600 
7601 // ---------------------------------------------------------------------------
7602 
7603 void TTrack::CheckMapAndInactiveTrack(int Caller) // test
7604 {
7605  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndInactiveTrack");
7606  bool FoundFlag;
7607  TIMPair InactivePair;
7608 
7609  for(unsigned int a = 0; a < InactiveTrackVector.size(); a++)
7610  {
7611  TTrackElement CheckElement = Track->InactiveTrackElementAt(142, a);
7612  InactivePair = GetVectorPositionsFromInactiveTrackMap(7, CheckElement.HLoc, CheckElement.VLoc, FoundFlag);
7613  if(!FoundFlag)
7614  {
7615  throw Exception("CheckMapAndInactiveTrack Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
7616  " in InactiveMap, Caller=" + (AnsiString)Caller);
7617  }
7618  if((InactivePair.first != a) && (InactivePair.second != a))
7619  {
7620  throw Exception("CheckMapAndInactiveTrack Error - InactiveMapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
7621  (AnsiString)CheckElement.VLoc + " Inactive Map values=" + (AnsiString)InactivePair.first + " and " + (AnsiString)InactivePair.second +
7622  " InactiveTrackVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
7623  }
7624  }
7625  if(InactiveTrackVector.size() != InactiveTrack2MultiMap.size())
7626  {
7627  throw Exception("CheckMapAndInactiveTrack Error - Map Size=" + (AnsiString)TrackVector.size() + " TrackVectorSize=" + (AnsiString)TrackVector.size() +
7628  " Caller=" + (AnsiString)Caller);
7629  }
7630  Utilities->CallLogPop(539);
7631 }
7632 
7633 // ---------------------------------------------------------------------------
7634 
7635 void TTrack::CheckGapMap(int Caller) // test
7636 {
7637  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckGapMap");
7638  int Position1, Position2;
7639  TTrackElement TrackElement1, TrackElement2;
7640  TGapMapIterator GapMapPtr;
7641 
7642  if(!GapMap.empty())
7643  {
7644  for(GapMapPtr = GapMap.begin(); GapMapPtr != GapMap.end(); GapMapPtr++)
7645  {
7646  int HLoc1 = GapMapPtr->first.first;
7647  int VLoc1 = GapMapPtr->first.second;
7648  int HLoc2 = GapMapPtr->second.first;
7649  int VLoc2 = GapMapPtr->second.second;
7650  if(!FindNonPlatformMatch(14, HLoc1, VLoc1, Position1, TrackElement1))
7651  {
7652  throw Exception("Failed to find H & V for gap1, GapMap in error");
7653  }
7654  if(!FindNonPlatformMatch(15, HLoc2, VLoc2, Position2, TrackElement2))
7655  {
7656  throw Exception("Failed to find H & V for gap2, GapMap in error");
7657  }
7658  if(TrackElementAt(17, Position1).TrackType != GapJump)
7659  {
7660  throw Exception("Element at Pos1 not a gap, GapMap in error");
7661  }
7662  if(TrackElementAt(18, Position2).TrackType != GapJump)
7663  {
7664  throw Exception("Element at Pos2 not a gap, GapMap in error");
7665  }
7666  }
7667  }
7668  unsigned int GapCount = 0;
7669 
7670  for(unsigned int a = 0; a < TrackVector.size(); a++)
7671  {
7672  TTrackElement CheckElement = Track->TrackElementAt(1355, a);
7673  if(CheckElement.TrackType == GapJump)
7674  {
7675  GapCount++;
7676  }
7677  }
7678  if((GapMap.size() * 2) != GapCount)
7679  {
7680  throw Exception("GapMap Error - Map Size * 2 =" + (AnsiString)(GapMap.size() * 2) + " GapCount=" + (AnsiString)GapCount + " Caller=" +
7681  (AnsiString)Caller);
7682  }
7683  Utilities->CallLogPop(540);
7684 }
7685 
7686 // ---------------------------------------------------------------------------
7687 
7688 void TTrack::SetElementID(int Caller, TTrackElement &TrackElement)
7689 {
7690  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetElementID," + TrackElement.LogTrack(5));
7691  if((TrackElement.HLoc == -2000000000) || (TrackElement.VLoc == -2000000000))
7692  {
7693  if(TrackFinished)
7694  {
7695  throw Exception("Error - TrackFinished with erase element still present");
7696  }
7697  Utilities->CallLogPop(541);
7698  return; // erased element, can't set ID
7699  }
7700  AnsiString IDString;
7701 
7702  if(TrackElement.HLoc < 0)
7703  {
7704  IDString = "N" + AnsiString(abs(TrackElement.HLoc)) + "-";
7705  }
7706  else
7707  {
7708  IDString = AnsiString(TrackElement.HLoc) + "-";
7709  }
7710  if(TrackElement.VLoc < 0)
7711  {
7712  IDString += "N" + AnsiString(abs(TrackElement.VLoc));
7713  }
7714  else
7715  {
7716  IDString += AnsiString(TrackElement.VLoc);
7717  }
7718  TrackElement.ElementID = IDString;
7719  Utilities->CallLogPop(542);
7720 }
7721 
7722 // ---------------------------------------------------------------------------
7723 
7724 int TTrack::GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
7725 {
7726 // e.g. "8-13", "00008-13", "N43-N127", etc
7727  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorPositionFromString, + String");
7728  int DelimPos;
7729 
7730  for(int x = 1; x < String.Length() + 1; x++)
7731  {
7732  if(String.IsDelimiter("-", x))
7733  {
7734  DelimPos = x;
7735  break;
7736  }
7737  if(x == String.Length())
7738  {
7739  if(GiveMessages)
7740  {
7741  ShowMessage("Error in track element identifier: <" + String + "> - no delimiter");
7742  }
7743  Utilities->CallLogPop(543);
7744  return(-1);
7745  }
7746  }
7747  if(DelimPos == 1)
7748  {
7749  if(GiveMessages)
7750  {
7751  ShowMessage("Error in track element identifier: <" + String + "> - No Horizontal value");
7752  }
7753  Utilities->CallLogPop(544);
7754  return(-1);
7755  }
7756  if(DelimPos == String.Length())
7757  {
7758  if(GiveMessages)
7759  {
7760  ShowMessage("Error in track element identifier <" + String + "> - No Vertical value");
7761  }
7762  Utilities->CallLogPop(545);
7763  return(-1);
7764  }
7765  if((String[String.Length()] < '0') || (String[String.Length()] > '9'))
7766  {
7767  if(GiveMessages)
7768  {
7769  ShowMessage("Error in track element identifier <" + String + "> - Last value is not a number");
7770  }
7771  Utilities->CallLogPop(1508);
7772  return(-1);
7773  }
7774  int HLoc, VLoc;
7775 
7776  if(String.SubString(1, 1) != "N")
7777  {
7778  for(int x = 1; x < DelimPos; x++)
7779  {
7780  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7781  {
7782  if(GiveMessages)
7783  {
7784  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7785  }
7786  Utilities->CallLogPop(546);
7787  return(-1);
7788  }
7789  }
7790  }
7791  if(String.SubString(1, 1) == "N")
7792  {
7793  for(int x = 2; x < DelimPos; x++)
7794  {
7795  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7796  {
7797  if(GiveMessages)
7798  {
7799  ShowMessage("Invalid character in Horizontal value in track element identifier: <" + String + ">");
7800  }
7801  Utilities->CallLogPop(763);
7802  return(-1);
7803  }
7804  }
7805  }
7806  if(String.SubString(1, 1) == "N")
7807  {
7808  HLoc = -(String.SubString(2, DelimPos - 2).ToInt());
7809  }
7810  else
7811  {
7812  HLoc = String.SubString(1, DelimPos - 1).ToInt();
7813  }
7814  if(String.SubString(DelimPos + 1, 1) != "N")
7815  {
7816  for(int x = DelimPos + 1; x < String.Length() + 1; x++)
7817  {
7818  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7819  {
7820  if(GiveMessages)
7821  {
7822  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7823  }
7824  Utilities->CallLogPop(547);
7825  return(-1);
7826  }
7827  }
7828  }
7829  if(String.SubString(DelimPos + 1, 1) == "N")
7830  {
7831  for(int x = DelimPos + 2; x < String.Length() + 1; x++)
7832  {
7833  if((String.SubString(x, 1) < "0") || (String.SubString(x, 1) > "9"))
7834  {
7835  if(GiveMessages)
7836  {
7837  ShowMessage("Invalid character in Vertical value in track element identifier: <" + String + ">");
7838  }
7839  Utilities->CallLogPop(764);
7840  return(-1);
7841  }
7842  }
7843  }
7844  if(String.SubString(DelimPos + 1, 1) == "N")
7845  {
7846  VLoc = -(String.SubString(DelimPos + 2, String.Length() - DelimPos - 1).ToInt());
7847  }
7848  else
7849  {
7850  VLoc = String.SubString(DelimPos + 1, String.Length() - DelimPos).ToInt();
7851  }
7852  THVPair HVPair(HLoc, VLoc);
7853  TTrackMapIterator TrackMapPtr;
7854 
7855  TrackMapPtr = TrackMap.find(HVPair);
7856  if(TrackMapPtr == TrackMap.end())
7857  {
7858  if(GiveMessages)
7859  {
7860  ShowMessage("No track element corresponding to track element identifier: <" + String + ">");
7861  }
7862  Utilities->CallLogPop(548);
7863  return(-1);
7864  }
7865  Utilities->CallLogPop(549);
7866  return(TrackMapPtr->second);
7867 }
7868 
7869 // ---------------------------------------------------------------------------
7870 
7871 bool TTrack::CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
7872 /*
7873  True for linked properly at both ends
7874 */
7875 {
7876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckFootCrossingLinks," + AnsiString(TrackElement.HLoc) + "," +
7877  AnsiString(TrackElement.VLoc) + "," + AnsiString(TrackElement.SpeedTag));
7878  int HLoc = TrackElement.HLoc;
7879  int VLoc = TrackElement.VLoc;
7880 
7881  if((TrackElement.SpeedTag != 129) && (TrackElement.SpeedTag != 130) && (TrackElement.SpeedTag != 145) && (TrackElement.SpeedTag != 146))
7882  {
7883  Utilities->CallLogPop(1821);
7884  return(false);
7885  }
7886  if(TrackElement.SpeedTag == 129) // vertical footbridge
7887  {
7888  // check top connection
7889  if(!(InactiveMapCheck(1, HLoc, VLoc, 76) // top plat
7890  || InactiveMapCheck(2, HLoc, VLoc - 1, 96) // concourse
7891  || InactiveMapCheck(3, HLoc, VLoc - 1, 77) // bot plat
7892  || ActiveMapCheck(4, HLoc, VLoc - 1, 129))) // vert footbridge
7893  {
7894  Utilities->CallLogPop(550);
7895  return(false);
7896  }
7897  // check bottom connection
7898  else if(!(InactiveMapCheck(4, HLoc, VLoc, 77) // bot plat
7899  || InactiveMapCheck(5, HLoc, VLoc + 1, 96) // concourse
7900  || InactiveMapCheck(6, HLoc, VLoc + 1, 76) // top plat
7901  || ActiveMapCheck(1, HLoc, VLoc + 1, 129))) // vert footbridge
7902  {
7903  Utilities->CallLogPop(551);
7904  return(false);
7905  }
7906  }
7907  if(TrackElement.SpeedTag == 145) // vertical underpass
7908  {
7909  // check top connection
7910  if(!(InactiveMapCheck(13, HLoc, VLoc, 76) // top plat
7911  || InactiveMapCheck(14, HLoc, VLoc - 1, 96) // concourse
7912  || InactiveMapCheck(15, HLoc, VLoc - 1, 77) // bot plat
7913  || ActiveMapCheck(5, HLoc, VLoc - 1, 145))) // vert u'pass
7914  {
7915  Utilities->CallLogPop(2114);
7916  return(false);
7917  }
7918  // check bottom connection
7919  else if(!(InactiveMapCheck(16, HLoc, VLoc, 77) // bot plat
7920  || InactiveMapCheck(17, HLoc, VLoc + 1, 96) // concourse
7921  || InactiveMapCheck(18, HLoc, VLoc + 1, 76) // top plat
7922  || ActiveMapCheck(6, HLoc, VLoc + 1, 145))) // vert u'pass
7923  {
7924  Utilities->CallLogPop(2115);
7925  return(false);
7926  }
7927  }
7928  if(TrackElement.SpeedTag == 130) // hor footbridge
7929  {
7930  // check left connection
7931  if(!(InactiveMapCheck(19, HLoc, VLoc, 78) // left plat
7932  || InactiveMapCheck(20, HLoc - 1, VLoc, 96) // concourse
7933  || InactiveMapCheck(21, HLoc - 1, VLoc, 79) // right plat
7934  || ActiveMapCheck(2, HLoc - 1, VLoc, 130))) // hor footbridge
7935  {
7936  Utilities->CallLogPop(552);
7937  return(false);
7938  }
7939  // check right connection
7940  else if(!(InactiveMapCheck(22, HLoc, VLoc, 79) // right plat
7941  || InactiveMapCheck(23, HLoc + 1, VLoc, 96) // concourse
7942  || InactiveMapCheck(24, HLoc + 1, VLoc, 78) // left plat
7943  || ActiveMapCheck(3, HLoc + 1, VLoc, 130))) // hor footbridge
7944  {
7945  Utilities->CallLogPop(553);
7946  return(false);
7947  }
7948  }
7949  if(TrackElement.SpeedTag == 146) // hor u'pass
7950  {
7951  // check left connection
7952  if(!(InactiveMapCheck(7, HLoc, VLoc, 78) // left plat
7953  || InactiveMapCheck(8, HLoc - 1, VLoc, 96) // concourse
7954  || InactiveMapCheck(9, HLoc - 1, VLoc, 79) // right plat
7955  || ActiveMapCheck(7, HLoc - 1, VLoc, 146))) // hor u'pass
7956  {
7957  Utilities->CallLogPop(2116);
7958  return(false);
7959  }
7960  // check right connection
7961  else if(!(InactiveMapCheck(10, HLoc, VLoc, 79) // right plat
7962  || InactiveMapCheck(11, HLoc + 1, VLoc, 96) // concourse
7963  || InactiveMapCheck(12, HLoc + 1, VLoc, 78) // left plat
7964  || ActiveMapCheck(8, HLoc + 1, VLoc, 146))) // hor u'pass
7965  {
7966  Utilities->CallLogPop(2117);
7967  return(false);
7968  }
7969  }
7970  Utilities->CallLogPop(554);
7971  return(true);
7972 }
7973 
7974 // ---------------------------------------------------------------------------
7975 
7976 bool TTrack::InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
7977 /*
7978  return true if the SpeedTag present in the map at H & V
7979 */
7980 {
7981  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
7982  AnsiString(SpeedTag));
7983  if(InactiveTrack2MultiMap.empty())
7984  {
7985  Utilities->CallLogPop(555);
7986  return(false);
7987  }
7988  THVPair HVPair(HLoc, VLoc);
7990  TInactiveTrack2MultiMapIterator HVIt1 = IMEnd, HVIt2 = IMEnd;
7991  TInactiveTrackRange HVRange = InactiveTrack2MultiMap.equal_range(HVPair);
7992 
7993  if(HVRange.first == HVRange.second)
7994  {
7995  Utilities->CallLogPop(556);
7996  return(false);
7997  }
7998  else
7999  {
8000  HVIt1 = HVRange.first;
8001  }
8002  TTrackElement Temp1, Temp2; // test
8003 
8004  Temp1 = InactiveTrackElementAt(8, HVIt1->second); // test
8005  if(--HVRange.second != HVRange.first)
8006  {
8007  HVIt2 = HVRange.second;
8008  Temp2 = InactiveTrackElementAt(9, HVIt2->second); // test
8009  }
8010  if((InactiveTrackElementAt(10, HVIt1->second).SpeedTag == SpeedTag) || ((HVIt2 != IMEnd) && (InactiveTrackElementAt(11,
8011  HVIt2->second).SpeedTag == SpeedTag)))
8012  {
8013  Utilities->CallLogPop(557);
8014  return(true);
8015  }
8016  else
8017  {
8018  Utilities->CallLogPop(558);
8019  return(false);
8020  }
8021 }
8022 
8023 // ---------------------------------------------------------------------------
8024 
8025 bool TTrack::ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
8026 /*
8027  return true if the SpeedTag present in the map at H & V
8028 */
8029 {
8030  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ActiveMapCheck," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8031  AnsiString(SpeedTag));
8032  if(TrackMap.empty())
8033  {
8034  Utilities->CallLogPop(559);
8035  return(false);
8036  }
8037  THVPair HVPair(HLoc, VLoc);
8038  TTrackMapIterator End = TrackMap.end();
8039  TTrackMapIterator It = End;
8040 
8041  It = TrackMap.find(HVPair);
8042  if((It != End) && (TrackElementAt(19, It->second).SpeedTag == SpeedTag))
8043  {
8044  Utilities->CallLogPop(560);
8045  return(true);
8046  }
8047  else
8048  {
8049  Utilities->CallLogPop(561);
8050  return(false);
8051  }
8052 }
8053 
8054 // ---------------------------------------------------------------------------
8055 
8056 void TTrack::EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
8057 {
8058 /*
8059  General:
8060  All platform, concourse, footcrossing & non-station named location elements are able to have a LocationName allocated, and track
8061  elements (including footcrossings) are able to have an ActiveTrackElementName allocated provided there is an adjacent platform or
8062  a NamedNonStationLocation.
8063  To set these names the user selects a single named location element (not a footcrossing), enters the name, and
8064  this is then allocated as a LocationName to all linked platform, concourse and footcrossing elements, and as an
8065  ActiveTrackElementName to all track elements adjacent to platforms (inc footcrossing tracks if (but only if) they have a
8066  platform at that location).
8067 
8068  Linked named location elements are those explained in TTrack::TTrack()
8069 
8070  Detail:
8071  Two containers are used for allocation of names - LNPendingList, and LNDone2MultiMap, each containing vector positions as
8072  integers and the Map using THVPairs as keys. An adjustment is made for the vector positions as follows:-
8073  inactive vector positions are stored as they are (since most NamedLocationElements are in the inactive vector), but active vector
8074  positions stored as (-1-True Position), so can hold both types in a single integer uniquely - not very elegant but it seems to
8075  work OK! e.g. TrackVector position 0 would be stored as -1, position n would be stored as -1-n. InactiveTrackVector position 0 would be stored as 0.
8076  To recover the true TrackVector position from a stored value the same rule applies, i.e. -1-stored value, equivalent to -1-(-1-original) = -1+1+original = original.
8077 
8078  The List holds elements that have still to be processed, and the Map holds elements that have been processed. On entering
8079  this function a single element should be in the List (normally from the user's selection but can also be from
8080  SearchForAndUpdateLocationName), and the Map is cleared within the function.
8081  A 'while' loop is entered if the List isn't empty, and the front element in it examined. All linked named location elements
8082  (platforms, concourses and footcrossings) that aren't already in either the Map or the List are first added to the List using
8083  AdjElement, then the element itself has it's LocationName set, and any relevant track elements at the same H & V (i.e. adjacent
8084  to a platform) have their ActiveTrackElementName set using AddName. The element is then inserted into the Map and erased from the List.
8085  In this way the list builds up while there are linked elements to be added, but reduces to zero when all are added and processing
8086  moves them into the Map. At the end all linked elements are in the Map.
8087 
8088  Finally any other element that isn't in the Map, i.e. not linked to the current named location, that has the same name as a
8089  LocationName or ActiveTrackElementName, has it erased. This is to allow for deletion of named location elements that split an existing
8090  named location - only one of the sides (selected by whichever the program finds first - the user can't select it) retains the name.
8091 */
8092 
8093 // AnsiString TestString = "H,V,Tag,List Size,DoneMultiMap Size,CurrentElementAddress,MultiMapEntryAddress";//test
8094 // Display->FileDiagnostics(TestString);//test
8095 
8096  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EnterLocationName," + LocationName);
8097  AnsiString TestString1, TestString2; // test
8098 
8099  Track->LNDone2MultiMap.clear();
8100  if(LNPendingList.size() != 1)
8101  {
8102  throw Exception("LNPendingList size not 1 on entry");
8103  }
8104  int CurrentElementNumber; //new after 2.4.3 due to error the JK found (Discord 9/7/20). See note below after 'if(AddingElements)' where CurrentElementNumber is used.
8105  while(!LNPendingList.empty())
8106  {
8107  CurrentElementNumber = LNPendingList.front();
8108  TTrackVectorIterator CurrentElement = GetTrackVectorIteratorFromNamePosition(1, CurrentElementNumber);
8109  int NewElement; // = 2000000000; //marker for unused //not needed from v1.2.0 Beta onwards
8110  int H = CurrentElement->HLoc;
8111  int V = CurrentElement->VLoc;
8112  int Tag = CurrentElement->SpeedTag;
8113  if(Tag == 76) // top plat
8114  {
8115  // AdjElement checks if there is an element matching Tag at H & V that isn't already in LNDone2MultiMap or LNPendingList,
8116  // & returns true if so with the adjusted vector position in NewElement. It checks the appropriate vector
8117  // depending on the SpeedTag value (footcrossings in active vector, rest in inactive vector),
8118  for(int x = 0; x < 25; x++)
8119  {
8120  if(AdjElement(1, H + Tag76Array[x][0], V + Tag76Array[x][1], Tag76Array[x][2], NewElement))
8121  {
8122  LNPendingList.insert(LNPendingList.end(), NewElement);
8123  }
8124  }
8125  }
8126  else if(Tag == 77) // bot plat
8127  {
8128  for(int x = 0; x < 25; x++)
8129  {
8130  if(AdjElement(2, H + Tag77Array[x][0], V + Tag77Array[x][1], Tag77Array[x][2], NewElement))
8131  {
8132  LNPendingList.insert(LNPendingList.end(), NewElement);
8133  }
8134  }
8135  }
8136  else if(Tag == 78) // l plat
8137  {
8138  for(int x = 0; x < 25; x++)
8139  {
8140  if(AdjElement(3, H + Tag78Array[x][0], V + Tag78Array[x][1], Tag78Array[x][2], NewElement))
8141  {
8142  LNPendingList.insert(LNPendingList.end(), NewElement);
8143  }
8144  }
8145  }
8146  else if(Tag == 79) // r plat
8147  {
8148  for(int x = 0; x < 25; x++)
8149  {
8150  if(AdjElement(4, H + Tag79Array[x][0], V + Tag79Array[x][1], Tag79Array[x][2], NewElement))
8151  {
8152  LNPendingList.insert(LNPendingList.end(), NewElement);
8153  }
8154  }
8155  }
8156  else if(Tag == 96) // conc
8157  {
8158  for(int x = 0; x < 28; x++)
8159  {
8160  if(AdjElement(5, H + Tag96Array[x][0], V + Tag96Array[x][1], Tag96Array[x][2], NewElement))
8161  {
8162  LNPendingList.insert(LNPendingList.end(), NewElement);
8163  }
8164  }
8165  }
8166  else if(Tag == 129) // vert footbridge
8167  {
8168  for(int x = 0; x < 8; x++)
8169  {
8170  if(AdjElement(6, H + Tag129Array[x][0], V + Tag129Array[x][1], Tag129Array[x][2], NewElement))
8171  {
8172  LNPendingList.insert(LNPendingList.end(), NewElement);
8173  }
8174  }
8175  }
8176  else if(Tag == 130) // hor footbridge
8177  {
8178  for(int x = 0; x < 8; x++)
8179  {
8180  if(AdjElement(7, H + Tag130Array[x][0], V + Tag130Array[x][1], Tag130Array[x][2], NewElement))
8181  {
8182  LNPendingList.insert(LNPendingList.end(), NewElement);
8183  }
8184  }
8185  }
8186  else if(Tag == 131) // named location
8187  {
8188  for(int x = 0; x < 4; x++)
8189  {
8190  if(AdjElement(8, H + Tag131Array[x][0], V + Tag131Array[x][1], Tag131Array[x][2], NewElement))
8191  {
8192  LNPendingList.insert(LNPendingList.end(), NewElement);
8193  }
8194  }
8195  }
8196  else if(Tag == 145) // v u'pass
8197  {
8198  for(int x = 0; x < 8; x++)
8199  {
8200  if(AdjElement(9, H + Tag145Array[x][0], V + Tag145Array[x][1], Tag145Array[x][2], NewElement))
8201  {
8202  LNPendingList.insert(LNPendingList.end(), NewElement);
8203  }
8204  }
8205  }
8206  else if(Tag == 146) // h u'pass
8207  {
8208  for(int x = 0; x < 8; x++)
8209  {
8210  if(AdjElement(10, H + Tag146Array[x][0], V + Tag146Array[x][1], Tag146Array[x][2], NewElement))
8211  {
8212  LNPendingList.insert(LNPendingList.end(), NewElement);
8213  }
8214  }
8215  }
8216  // below new at v1.1.0 but condition changed at v1.1.4 as interfered with name changes for single element locations
8217 // if(NewElement != 2000000000) //adjacent element found & new element inserted, check if a (different) name already allocated and if so erase it from text vector
8218  if(AddingElements)
8219  {
8220  int HPos, VPos; // not used but needed for FindText function
8221  if(CurrentElementNumber > -1) //up to & including 2.4.2 this was NewElement, which was the last one added during LNPendingList building above, so it could be
8222  //repeatedly selected rather than the element under examination (LNPendingList.front()) & the front element text name wouldn't be erased.
8223  //Using CurrentElementNumber ensures that all elements are examined & have names erased if present
8224  {
8225  AnsiString ExistingName = InactiveTrackElementAt(118, CurrentElementNumber).LocationName; //existing name of CurrentElement
8226  if((ExistingName != "") && (ExistingName != LocationName))
8227  {
8228  if(LocationNameMultiMap.find(ExistingName) == Track->LocationNameMultiMap.end())
8229  {
8230  } // name not in LocationNameMultiMap, so don't erase from TextVector
8231  else if(TextHandler->FindText(4, ExistingName, HPos, VPos)) // can't use 'EraseLocationNameText' as that function is in TInterface
8232  {
8233  if(TextHandler->TextErase(10, HPos, VPos, ExistingName))
8234  {
8235  ;
8236  } // condition not used
8237 
8238  }
8239  }
8240  }
8241  }
8242  AddName(1, CurrentElement, LocationName); // add location name to current element, + timetable name to any
8243  // track at that loc
8244  THVPair HVPair(H, V);
8245  TLNDone2MultiMapEntry LNDone2MultiMapEntry;
8246  LNDone2MultiMapEntry.first = HVPair;
8247  LNDone2MultiMapEntry.second = LNPendingList.front();
8248  LNDone2MultiMap.insert(LNDone2MultiMapEntry);
8249  LNPendingList.erase(LNPendingList.begin());
8250  }
8251 
8252 // search all name multimap for same name where corresponding active elements don't appear in
8253 // LNDone2MultiMap & erase the name for all elements at that H & V in both active & inactive vectors
8254 
8255  TLocationNameMultiMapIterator SNIterator;
8256  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8257  bool FoundFlag, ErasedFlag = false;
8258 
8259  if(SNRange.first != SNRange.second)
8260  {
8261  SNRange.first--; // now pointing to before the first
8262  SNRange.second--; // now pointing to the last
8263  for(SNIterator = SNRange.second; SNIterator != SNRange.first; SNIterator--)
8264  {
8265  // Same elements are in Done map as in name map
8266  if(!ElementInLNDone2MultiMap(1, SNIterator->second))
8267  {
8268  ErasedFlag = true;
8269  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(2, SNIterator->second);
8270  TVIt->LocationName = "";
8271  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8272  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform)
8273  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8274  {
8275  int Position = GetVectorPositionFromTrackMap(17, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8276  if(FoundFlag)
8277  {
8278  TrackElementAt(20, Position).LocationName = "";
8279  TrackElementAt(21, Position).ActiveTrackElementName = "";
8280  }
8281  }
8282  // erase name in name map
8283 // ChangeLocationNameMultiMapEntry("", SNIterator); can't use this as interferes with the iterators
8284  }
8285  }
8286  }
8287  if(ErasedFlag)
8288  {
8290  }
8291  if(TrackFinished)
8292  {
8294  }
8295 // set here as well as in LinkTrack so don't have to link track just because a name added
8296 // if track not finished then will be set when track validated
8297 
8298 // Rebuild ContinuationNameMap - added at v2.6.1 due to error found by Andrekoener & notified by discord on 16/12/20
8299 // error was that if a continuation name was changed and a timetable stopping place included that new name then ContinuationNameMap wouldn't be rebuilt
8300 // so the timetable would validate and load and the name would appear in the dropdown list. The reason was that ContinuationNameMap was only built in TryToLinkTrack,
8301 // so if that isn't called (as it isn't for a name change) then the error wouldn't be seen. However next time the railway was loaded TryToLinkTrack was called
8302 // so the error would be seen.
8303 // This inclusion rebuilds ContinuationNameMap whenever a name is entered or changed so the error can no longer be hidden.
8304  std::pair<AnsiString, char>TempMapPair;
8305 
8306  ContinuationNameMap.clear();
8307  for(int x = 0; x < Track->TrackVectorSize(); x++)
8308  {
8309  if((Track->TrackElementAt(1356, x).TrackType == Continuation) && (Track->TrackElementAt(1357, x).ActiveTrackElementName != ""))
8310  {
8311  TempMapPair.first = Track->TrackElementAt(1358, x).ActiveTrackElementName;
8312  TempMapPair.second = 'x'; // unused
8313  ContinuationNameMap.insert(TempMapPair);
8314  }
8315  }
8316 //end of addition
8317  CheckLocationNameMultiMap(1); // test
8318  Utilities->CallLogPop(562);
8319 }
8320 
8321 // ---------------------------------------------------------------------------
8322 
8323 bool TTrack::AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
8324 /*
8325  Looks for a FixedNamedLocationElement at H & V with SpeedTag, and if found and not already present in either the
8326  LNDone2MultiMap or the LNPendingList returns an int corresponding to the adjusted vector position.
8327 */
8328 {
8329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8330  AnsiString(SpeedTag));
8331  if(!NamedLocationElementAt(2, HLoc, VLoc))
8332  {
8333  Utilities->CallLogPop(948);
8334  return(false);
8335  }
8336  bool FoundFlag;
8337  int Position = -1;
8338  TIMPair IMPair;
8339 
8340  if((SpeedTag == 129) || (SpeedTag == 130) || (SpeedTag == 145) || (SpeedTag == 146)) // footcrossing - only in active vector
8341  {
8342  Position = GetVectorPositionFromTrackMap(18, HLoc, VLoc, FoundFlag);
8343  if(FoundFlag)
8344  {
8345  if(TrackElementAt(22, Position).SpeedTag == SpeedTag)
8346  {
8347  int MapPos = -1 - Position; // MapPos is the adjusted entry in the list & map
8348  if(!ElementInLNDone2MultiMap(2, MapPos) && !ElementInLNPendingList(1, MapPos))
8349  // don't allow duplicates in either list, or processing takes a lot longer
8350  {
8351  FoundElement = MapPos;
8352  Utilities->CallLogPop(563);
8353  return(true);
8354  }
8355  }
8356  }
8357  }
8358  else
8359  {
8360  IMPair = GetVectorPositionsFromInactiveTrackMap(8, HLoc, VLoc, FoundFlag);
8361  if(FoundFlag)
8362  {
8363  if(InactiveTrackElementAt(12, IMPair.first).SpeedTag == SpeedTag)
8364  {
8365  if(!ElementInLNDone2MultiMap(3, IMPair.first) && !ElementInLNPendingList(2, IMPair.first))
8366  {
8367  FoundElement = IMPair.first;
8368  Utilities->CallLogPop(564);
8369  return(true);
8370  }
8371  }
8372  else if(InactiveTrackElementAt(13, IMPair.second).SpeedTag == SpeedTag)
8373  {
8374  if(!ElementInLNDone2MultiMap(4, IMPair.second) && !ElementInLNPendingList(3, IMPair.second))
8375  {
8376  FoundElement = IMPair.second;
8377  Utilities->CallLogPop(565);
8378  return(true);
8379  }
8380  }
8381  }
8382  }
8383  Utilities->CallLogPop(566);
8384  return(false);
8385 }
8386 
8387 // ---------------------------------------------------------------------------
8388 
8389 void TTrack::AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
8390 /*
8391  Add location name to TrackElement and ActiveTrackElementName to any elements in trackmap
8392  at same H & V if TrackElement is a Platform or named non-station location. Also update LocationNameMultiMap
8393  with the new name
8394 */
8395 {
8396  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddName," + TrackElement->LogTrack(6) + "," + Name);
8397  AnsiString OldName = TrackElement->LocationName, ErrorString; // declare new AnsiStrings OldName (set to existing name) & ErrorString
8398 
8399  TrackElement->LocationName = Name; // covers all FixedNamedLocationElement whichever vector they are in
8400  int HLoc = TrackElement->HLoc;
8401  int VLoc = TrackElement->VLoc;
8402  bool FoundFlag;
8403 
8404  if((TrackElement->TrackType == Platform) || (TrackElement->TrackType == NamedNonStationLocation))
8405  // only have timetable names for adjacent platforms & named locations
8406  {
8407  int Position = GetVectorPositionFromTrackMap(19, HLoc, VLoc, FoundFlag);
8408  if(FoundFlag)
8409  {
8410  TrackElementAt(23, Position).ActiveTrackElementName = Name;
8411  }
8412  }
8413  TLocationNameMultiMapIterator SNIterator = FindNamedElementInLocationNameMultiMap(4, OldName, TrackElement, ErrorString);
8414 
8415  if(ErrorString != "")
8416  {
8417  throw Exception(ErrorString + " in AddName for OldName == " + OldName);
8418  }
8419  ChangeLocationNameMultiMapEntry(1, Name, SNIterator); // OK, can use it here as not in an iterator loop
8420  CheckLocationNameMultiMap(2); // test
8421  Utilities->CallLogPop(567);
8422 }
8423 
8424 // ---------------------------------------------------------------------------
8425 
8426 bool TTrack::ElementInLNDone2MultiMap(int Caller, int MapPos)
8427 /*
8428  Examines LNDone2MultiMap to see whether the MapPos value is present, and returns true if so.
8429 */
8430 {
8431  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNDone2MultiMap," + AnsiString(MapPos));
8432  if(LNDone2MultiMap.empty())
8433  {
8434  Utilities->CallLogPop(568);
8435  return(false);
8436  }
8437  TLNDone2MultiMapIterator LNDone2MultiMapIterator;
8438 
8439  for(LNDone2MultiMapIterator = LNDone2MultiMap.begin(); LNDone2MultiMapIterator != LNDone2MultiMap.end(); LNDone2MultiMapIterator++)
8440  {
8441  if(LNDone2MultiMapIterator->second == MapPos)
8442  {
8443  Utilities->CallLogPop(569);
8444  return(true);
8445  }
8446  }
8447  Utilities->CallLogPop(570);
8448  return(false);
8449 }
8450 
8451 // ---------------------------------------------------------------------------
8452 
8453 bool TTrack::ElementInLNPendingList(int Caller, int MapPos)
8454 /*
8455  Examines LNPendingList to see whether the MapPos value is present, and returns true if so.
8456 */
8457 {
8458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ElementInLNPendingList," + AnsiString(MapPos));
8459  if(LNPendingList.empty())
8460  {
8461  Utilities->CallLogPop(571);
8462  return(false);
8463  }
8464  TLNPendingListIterator LNPendingListIterator;
8465 
8466  for(LNPendingListIterator = LNPendingList.begin(); LNPendingListIterator != LNPendingList.end(); LNPendingListIterator++)
8467  {
8468  if(*LNPendingListIterator == MapPos)
8469  {
8470  Utilities->CallLogPop(572);
8471  return(true);
8472  }
8473  }
8474  Utilities->CallLogPop(573);
8475  return(false);
8476 }
8477 
8478 // ---------------------------------------------------------------------------
8479 
8480 bool TTrack::NamedLocationElementAt(int Caller, int HLoc, int VLoc)
8481 /*
8482  Examines element at H & V, and returns true if its FixedNamedLocationElement bool is true
8483 */
8484 {
8485  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NamedLocationElementAt," + AnsiString(HLoc) + "," + AnsiString(VLoc));
8486  THVPair HVPair(HLoc, VLoc);
8487  TTrackMapIterator TrackMapPtr = TrackMap.find(HVPair);
8488  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.find(HVPair);
8489 
8490  if(TrackMapPtr != TrackMap.end()) // =end() if not found
8491  {
8492  if(TrackElementAt(24, TrackMapPtr->second).FixedNamedLocationElement)
8493  {
8494  Utilities->CallLogPop(574);
8495  return(true);
8496  }
8497  }
8498  if(InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end())
8499  // may be 2 platforms at location but if so both FixedNamedLocationElement bools will be set, so only need to find one
8500  {
8501  if(InactiveTrackElementAt(14, InactiveTrack2MultiMapIterator->second).FixedNamedLocationElement)
8502  {
8503  Utilities->CallLogPop(575);
8504  return(true);
8505  }
8506  }
8507  Utilities->CallLogPop(576);
8508  return(false);
8509 }
8510 
8511 // ---------------------------------------------------------------------------
8512 
8513 bool TTrack::LocationNameAllocated(int Caller, AnsiString LocationName) // true if a non-empty LocationName found in LocationNameMultiMap
8514 {
8515  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LocationNameAllocated," + LocationName);
8516  if(Track->LocationNameMultiMap.find(LocationName) != Track->LocationNameMultiMap.end())
8517  {
8518  Utilities->CallLogPop(1953);
8519  return(true);
8520  }
8521  Utilities->CallLogPop(1954);
8522  return(false);
8523 }
8524 
8525 // ---------------------------------------------------------------------------
8526 
8527 bool TTrack::DuplicatedLocationName(int Caller, bool GiveMessage)
8528 //examines LocationNameMultiMap and returns true if there are two or more locations with the same name - added at v2.6.1 to cater for Bill78's new .dev file merge
8529 //program and used when try to save as a .rly file
8530 {
8531  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DuplicatedLocationName");
8534  if(LocationNameMultiMap.empty()) //no names so no duplicates
8535  {
8536  Utilities->CallLogPop(2254);
8537  return(false);
8538  }
8539  AnsiString NameBeingChecked = LocationNameMultiMap.begin()->first; //first name to start with
8540  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked);
8541  if(NameBeingChecked != "") //added for v2.6.2 as 2.6.1 reported duplicate null names (reported by Micke(Commuterpop) 06/01/21 via discord)
8542  {
8544  {
8545  if(GiveMessage)
8546  {
8547  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8548  }
8549  Utilities->CallLogPop(2255);
8550  return(true);
8551  }
8552  }
8553  while(LNMMRg.second != LocationNameMultiMap.end()) //here LNMMRg still set to earlier name
8554  {
8555  NameBeingChecked = LNMMRg.second->first; //this is the next name as LNMMRg->second points to the first location NOT containing the first name
8556  LNMMRg = LocationNameMultiMap.equal_range(NameBeingChecked); //here LNMMRg is the new range
8557  if(NameBeingChecked != "") //should have skipped all null names as all listed together but add to be on the safe side
8558  {
8560  {
8561  if(GiveMessage)
8562  {
8563  ShowMessage("Please note that more than one instance of " + NameBeingChecked + " was found. Location names must be unique before the railway can be saved as a .rly file");
8564  }
8565  Utilities->CallLogPop(2256);
8566  return(true);
8567  }
8568  }
8569  }
8570  Utilities->CallLogPop(2257);
8571  return(false); //OK, no duplicates
8572 }
8573 
8574 // ---------------------------------------------------------------------------
8575 
8577 {
8578  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateHVPairsLinkedMapAndNoDuplicates");
8579  THVPair HVPair;
8580  THVPairsLinkedMap HVPairsLinkedMap; //this is a map of HVPairs (so each is unique), each with a boolean marker, false for not linked and true for linked
8581  //for use in the duplicate check
8582  for(TLocationNameMultiMapIterator LNMMIt = LNMMRg.first; LNMMIt != LNMMRg.second; LNMMIt++) //populating the linked map
8583  {
8584  if(LNMMIt->second < 0) //active track element
8585  {
8586  HVPair.first = TrackElementAt(1011, (-1 - LNMMIt->second)).HLoc;
8587  HVPair.second = TrackElementAt(1012, (-1 - LNMMIt->second)).VLoc;
8588  }
8589  else //inactive track element
8590  {
8591  HVPair.first = InactiveTrackElementAt(134, LNMMIt->second).HLoc;
8592  HVPair.second = InactiveTrackElementAt(135, LNMMIt->second).VLoc;
8593  }
8594  HVPairsLinkedMap.insert(std::pair<THVPair, bool>(HVPair, false)); //set all bools to false initially
8595  }
8596  //All HVPairs now present in HVPairsLinkedMap for the specific location name
8597 
8598  //now need to identify all named elements that are linked either vertically or horizontally with the first one (could be any but must be just one)
8599  //so that at the end any that haven't been identified aren't linked and so represent a duplicated name
8600  //to do so need a list (works like LNPendingList) to hold all elements that haven't been checked for links
8601 
8602  std::list<THVPair> HVLinkedList;
8603 
8604  //set the first value to true and add it to the list
8605  HVPairsLinkedMap.begin()->second = true;
8606  HVLinkedList.push_back(HVPairsLinkedMap.begin()->first);
8607  //now enter a loop to examine the front pair in the list and set all linked bools to true, and if they weren't already true then add them to the back of the list for later
8608  //examination
8609  THVPair HVPairUnderExamination;
8610  THVPairsLinkedMap::iterator HVPLMIt;
8611  THVPair HVPairNew;
8612  while(!HVLinkedList.empty())
8613  {
8614  HVPairUnderExamination = HVLinkedList.front();
8615  HVLinkedList.pop_front();
8616  HVPairNew.first = HVPairUnderExamination.first;
8617  HVPairNew.second = HVPairUnderExamination.second - 1; //position directly above element
8618  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8619  if(HVPLMIt != HVPairsLinkedMap.end())
8620  {
8621  if(!HVPLMIt->second)
8622  {
8623  HVLinkedList.push_back(HVPLMIt->first);
8624  }
8625  HVPLMIt->second = true;
8626  }
8627  HVPairNew.first = HVPairUnderExamination.first - 1;
8628  HVPairNew.second = HVPairUnderExamination.second; //position to the left of the element
8629  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8630  if(HVPLMIt != HVPairsLinkedMap.end())
8631  {
8632  if(!HVPLMIt->second)
8633  {
8634  HVLinkedList.push_back(HVPLMIt->first);
8635  }
8636  HVPLMIt->second = true;
8637  }
8638  HVPairNew.first = HVPairUnderExamination.first;
8639  HVPairNew.second = HVPairUnderExamination.second + 1; //position under the element
8640  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8641  if(HVPLMIt != HVPairsLinkedMap.end())
8642  {
8643  if(!HVPLMIt->second)
8644  {
8645  HVLinkedList.push_back(HVPLMIt->first);
8646  }
8647  HVPLMIt->second = true;
8648  }
8649  HVPairNew.first = HVPairUnderExamination.first + 1;
8650  HVPairNew.second = HVPairUnderExamination.second; //position to the right of the element
8651  HVPLMIt = HVPairsLinkedMap.find(HVPairNew);
8652  if(HVPLMIt != HVPairsLinkedMap.end())
8653  {
8654  if(!HVPLMIt->second)
8655  {
8656  HVLinkedList.push_back(HVPLMIt->first);
8657  }
8658  HVPLMIt->second = true;
8659  }
8660  }
8661 
8662  //at the end if any have a false bool then the name is duplicated so return false
8663  for(THVPairsLinkedMap::iterator HVPLMIt = HVPairsLinkedMap.begin(); HVPLMIt != HVPairsLinkedMap.end(); HVPLMIt++)
8664  {
8665  if(!HVPLMIt->second)
8666  {
8667  Utilities->CallLogPop(2258);
8668  return(false);
8669  }
8670  }
8671  Utilities->CallLogPop(2259);
8672  return(true);
8673 }
8674 
8675 // ---------------------------------------------------------------------------
8676 
8677 bool TTrack::TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
8678 /*
8679  Examines ActiveTrackElementNameMap and returns true if the LocationName is found and isn't "" (used to use LocationNameMultiMap)
8680 */
8681 
8682 {
8683  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TimetabledLocationNameAllocated," + LocationName);
8684  if(LocationName == "")
8685  {
8686  Utilities->CallLogPop(577);
8687  return(false);
8688  }
8689 // new for v0.2b
8690 // compile ActiveTrackElementNameMap if !ActiveTrackElementNameMapCompiledFlag (added as a precaution, should be compiled when reach here)
8692  {
8693  TActiveTrackElementNameMapEntry ActiveTrackElementNameMapEntry;
8694  ActiveTrackElementNameMap.clear();
8695  for(unsigned int x = 0; x < TrackVector.size(); x++)
8696  {
8697  if((TrackElementAt(1359, x).ActiveTrackElementName != "") && (ContinuationNameMap.find(TrackElementAt(1360, x).ActiveTrackElementName))
8698  == ContinuationNameMap.end())
8699  {
8700  // exclude any name that appears in a continuation, error message given in tt validation if try to include such a name in a tt
8701  ActiveTrackElementNameMapEntry.first = Track->TrackElementAt(1361, x).ActiveTrackElementName;
8702  ActiveTrackElementNameMapEntry.second = 0; // this is a dummy value
8703  ActiveTrackElementNameMap.insert(ActiveTrackElementNameMapEntry);
8704  }
8705  }
8707  }
8708  Utilities->CallLogPop(578);
8709  return (ActiveTrackElementNameMap.find(LocationName) != ActiveTrackElementNameMap.end());
8710 // end of new section
8711 // return (LocationNameMultiMap.find(LocationName) != LocationNameMultiMap.end());
8712 }
8713 
8714 // ---------------------------------------------------------------------------
8715 
8716 void TTrack::EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
8717 /*
8718  Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both active and inactive vectors) have the
8719  name erased both as a LocationName and a ActiveTrackElementName. The LocationNameMultiMap is also rebuilt to correspond to the
8720  new names in the vectors.
8721 */
8722 {
8723  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseLocationAndActiveTrackElementNames," + LocationName);
8724  bool FoundFlag, ErasedFlag = false;
8725  TLocationNameMultiMapIterator SNIterator;
8726  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
8727 
8728  if(SNRange.first != SNRange.second)
8729  {
8730  ErasedFlag = true;
8731  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
8732  {
8733  TTrackVectorIterator TVIt = GetTrackVectorIteratorFromNamePosition(3, SNIterator->second);
8734  TVIt->LocationName = "";
8735  TVIt->ActiveTrackElementName = ""; // in case it's a footcrossing
8736  // need to erase the timetable name in a track element at same H&V if present (i.e. if a platform or namedlocation)
8737  if((TVIt->TrackType == Platform) || (TVIt->TrackType == NamedNonStationLocation))
8738  {
8739  int Position = GetVectorPositionFromTrackMap(20, TVIt->HLoc, TVIt->VLoc, FoundFlag);
8740  if(FoundFlag)
8741  {
8742  TrackElementAt(25, Position).LocationName = "";
8743  TrackElementAt(26, Position).ActiveTrackElementName = "";
8744  }
8745  }
8746  }
8747  }
8748  if(ErasedFlag)
8749  {
8751  }
8752  CheckLocationNameMultiMap(3); // test
8753  Utilities->CallLogPop(579);
8754 }
8755 
8756 // ---------------------------------------------------------------------------
8757 
8758 void TTrack::SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
8759 /*
8760  NB No longer used during EraseTrackElement, too long-winded - erase all name now if any part removed, user needs to re-enter
8761  Checks all locations that are adjacent to the one entered for linked named location elements, and if any LocationName is found
8762  in any of the linked elements that name is used for all elements that are now linked to it. The location entered doesn't
8763  need to be a FixedNamedLocationElement and there doesn't even need to be an element there. Used during EraseTrackElement (in which
8764  case the SpeedTag is that for the element that is erased) and PlotAndAddTrackElement, to bring the named location and timetable
8765  naming up to date with the deletion or insertion.
8766 */
8767 {
8768  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForAndUpdateLocationName," + AnsiString(HLoc) + "," +
8769  AnsiString(VLoc) + "," + AnsiString(SpeedTag));
8770  LNPendingList.clear();
8771  AnsiString LocationName;
8772  int MapPos;
8773  bool FoundFlag = 0;
8774 
8775 //first check if this element is inactive and named, and if so use its position and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8776  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(30, HLoc, VLoc, FoundFlag);
8777  if(FoundFlag)
8778  {
8779  LocationName = InactiveTrackElementAt(132, IMPair.first).LocationName;
8780  if(LocationName != "")
8781  {
8782  LNPendingList.insert(Track->LNPendingList.end(), IMPair.first);
8783  EnterLocationName(13, LocationName, true);
8784  Utilities->CallLogPop(2251);
8785  return;
8786  }
8787  LocationName = InactiveTrackElementAt(133, IMPair.second).LocationName;
8788  if(LocationName != "")
8789  {
8790  LNPendingList.insert(Track->LNPendingList.end(), IMPair.second);
8791  EnterLocationName(14, LocationName, true);
8792  Utilities->CallLogPop(2252);
8793  return;
8794  }
8795  }
8796 //then check if this element is active and named, and if so use its position (-Pos-1) and name (new at v2.6.0 to allow pasted named locations to name linked elements)
8797 
8798  int Position = GetVectorPositionFromTrackMap(59, HLoc, VLoc, FoundFlag);
8799  if(FoundFlag)
8800  {
8801  LocationName = TrackElementAt(1004, Position).LocationName;
8802  if(LocationName != "")
8803  {
8804  int ModifiedPosition = -1 - Position;
8805  LNPendingList.insert(Track->LNPendingList.end(), ModifiedPosition);
8806  EnterLocationName(15, LocationName, true);
8807  Utilities->CallLogPop(2253);
8808  return;
8809  }
8810  }
8811  if(SpeedTag == 76) // top plat
8812  {
8813  for(int x = 0; x < 25; x++)
8814  {
8815  if(AdjNamedElement(1, HLoc + Tag76Array[x][0], VLoc + Tag76Array[x][1], Tag76Array[x][2], LocationName, MapPos))
8816  {
8817  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8818  EnterLocationName(3, LocationName, true);
8819  break;
8820  }
8821  }
8822  }
8823  else if(SpeedTag == 77) // bot plat
8824  {
8825  for(int x = 0; x < 25; x++)
8826  {
8827  if(AdjNamedElement(2, HLoc + Tag77Array[x][0], VLoc + Tag77Array[x][1], Tag77Array[x][2], LocationName, MapPos))
8828  {
8829  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8830  EnterLocationName(4, LocationName, true);
8831  break;
8832  }
8833  }
8834  }
8835  else if(SpeedTag == 78) // l plat
8836  {
8837  for(int x = 0; x < 25; x++)
8838  {
8839  if(AdjNamedElement(3, HLoc + Tag78Array[x][0], VLoc + Tag78Array[x][1], Tag78Array[x][2], LocationName, MapPos))
8840  {
8841  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8842  EnterLocationName(5, LocationName, true);
8843  break;
8844  }
8845  }
8846  }
8847  else if(SpeedTag == 79) // r plat
8848  {
8849  for(int x = 0; x < 25; x++)
8850  {
8851  if(AdjNamedElement(4, HLoc + Tag79Array[x][0], VLoc + Tag79Array[x][1], Tag79Array[x][2], LocationName, MapPos))
8852  {
8853  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8854  EnterLocationName(6, LocationName, true);
8855  break;
8856  }
8857  }
8858  }
8859  else if(SpeedTag == 96) // conc
8860  {
8861  for(int x = 0; x < 28; x++)
8862  {
8863  if(AdjNamedElement(5, HLoc + Tag96Array[x][0], VLoc + Tag96Array[x][1], Tag96Array[x][2], LocationName, MapPos))
8864  {
8865  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8866  EnterLocationName(7, LocationName, true);
8867  break;
8868  }
8869  }
8870  }
8871  else if(SpeedTag == 129) // vert footbridge
8872  {
8873  for(int x = 0; x < 8; x++)
8874  {
8875  if(AdjNamedElement(6, HLoc + Tag129Array[x][0], VLoc + Tag129Array[x][1], Tag129Array[x][2], LocationName, MapPos))
8876  {
8877  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8878  EnterLocationName(8, LocationName, true);
8879  break;
8880  }
8881  }
8882  }
8883  else if(SpeedTag == 130) // hor footbridge
8884  {
8885  for(int x = 0; x < 8; x++)
8886  {
8887  if(AdjNamedElement(7, HLoc + Tag130Array[x][0], VLoc + Tag130Array[x][1], Tag130Array[x][2], LocationName, MapPos))
8888  {
8889  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8890  EnterLocationName(9, LocationName, true);
8891  break;
8892  }
8893  }
8894  }
8895  else if(SpeedTag == 145) // vert u'pass
8896  {
8897  for(int x = 0; x < 8; x++)
8898  {
8899  if(AdjNamedElement(9, HLoc + Tag145Array[x][0], VLoc + Tag145Array[x][1], Tag145Array[x][2], LocationName, MapPos))
8900  {
8901  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8902  EnterLocationName(11, LocationName, true);
8903  break;
8904  }
8905  }
8906  }
8907  else if(SpeedTag == 146) // hor u'pass
8908  {
8909  for(int x = 0; x < 8; x++)
8910  {
8911  if(AdjNamedElement(10, HLoc + Tag146Array[x][0], VLoc + Tag146Array[x][1], Tag146Array[x][2], LocationName, MapPos))
8912  {
8913  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8914  EnterLocationName(12, LocationName, true);
8915  break;
8916  }
8917  }
8918  }
8919  else if(SpeedTag == 131) // named location
8920  {
8921  for(int x = 0; x < 4; x++)
8922  {
8923  if(AdjNamedElement(8, HLoc + Tag131Array[x][0], VLoc + Tag131Array[x][1], Tag131Array[x][2], LocationName, MapPos))
8924  {
8925  LNPendingList.insert(Track->LNPendingList.end(), MapPos);
8926  EnterLocationName(10, LocationName, true);
8927  break;
8928  }
8929  }
8930  }
8931 // AddName(HLoc, VLoc, LocationName);//don't need this now, EnterLocationName takes care of it
8932  Utilities->CallLogPop(580);
8933 }
8934 
8935 // ---------------------------------------------------------------------------
8936 
8937 bool TTrack::AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
8938 /*
8939  Used in SearchForAndUpdateLocationName to check for elements in TrackMap & InactiveTrackMap that match H, V & Tag, & returns
8940  true if a LocationName is found, and also returns the name and the adjusted vector position.
8941 */
8942 {
8943  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AdjNamedElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
8944  AnsiString(SpeedTag));
8945  bool FoundFlag;
8946  TIMPair IMPair;
8947  TTrackVectorIterator TempElement;
8948  int Position;
8949 
8950  IMPair = GetVectorPositionsFromInactiveTrackMap(9, HLoc, VLoc, FoundFlag);
8951  if(FoundFlag)
8952  {
8953  if(InactiveTrackElementAt(15, IMPair.first).SpeedTag == SpeedTag)
8954  {
8955  TempElement = InactiveTrackVector.begin() + IMPair.first;
8956  if(TempElement->LocationName != "")
8957  {
8958  LocationName = TempElement->LocationName;
8959  FoundElement = IMPair.first;
8960  Utilities->CallLogPop(581);
8961  return(true);
8962  }
8963  }
8964  else if(InactiveTrackElementAt(16, IMPair.second).SpeedTag == SpeedTag)
8965  {
8966  TempElement = InactiveTrackVector.begin() + IMPair.second;
8967  if(TempElement->LocationName != "")
8968  {
8969  LocationName = TempElement->LocationName;
8970  FoundElement = IMPair.second;
8971  Utilities->CallLogPop(582);
8972  return(true);
8973  }
8974  }
8975  }
8976  Position = GetVectorPositionFromTrackMap(21, HLoc, VLoc, FoundFlag);
8977  if(FoundFlag)
8978  {
8979  if(TrackElementAt(27, Position).SpeedTag == SpeedTag)
8980  {
8981  TempElement = TrackVector.begin() + Position;
8982  if(TempElement->LocationName != "")
8983  {
8984  LocationName = TempElement->LocationName;
8985  FoundElement = -1 - Position;
8986  Utilities->CallLogPop(583);
8987  return(true);
8988  }
8989  }
8990  }
8991  Utilities->CallLogPop(584);
8992  return(false);
8993 }
8994 
8995 // ---------------------------------------------------------------------------
8996 
8997 void TTrack::CheckLocationNameMultiMap(int Caller) // test function
8998 {
8999 // check quantity in map & vectors match
9000  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckLocationNameMultiMap,");
9001  unsigned int Count = 0;
9002 
9003  if(SkipLocationNameMultiMapCheck) // renamed in v2.4.0 to skip check when pasting because fails as map elements not fully aligned until all pasted
9004  {
9005  Utilities->CallLogPop(2059);
9006  return;
9007  }
9008  AnsiString SName, TName, ErrorString;
9009 
9010  for(unsigned int x = 0; x < TrackVector.size(); x++)
9011  {
9012  if(TrackElementAt(1362, x).FixedNamedLocationElement)
9013  {
9014  if(TrackElementAt(1363, x).TrackType != FootCrossing)
9015  {
9016  throw Exception("Track element has FixedNamedLocationElement set but is not a footbridge/underpass in CheckLocationNameMultiMap, caller = " +
9017  AnsiString(Caller));
9018  }
9019  Count++;
9020  }
9021  }
9022  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9023  {
9024  if(InactiveTrackElementAt(143, x).FixedNamedLocationElement)
9025  {
9026  if((InactiveTrackElementAt(144, x).TrackType != Platform) && (InactiveTrackElementAt(145, x).TrackType != NamedNonStationLocation) &&
9027  (InactiveTrackElementAt(146, x).TrackType != Concourse))
9028  {
9029  throw Exception
9030  ("Inactive track element has FixedNamedLocationElement set but is not a platform, concourse or named location in CheckLocationNameMultiMap, caller = " +
9031  AnsiString(Caller));
9032  }
9033  Count++;
9034  }
9035  }
9036  if(LocationNameMultiMap.size() != Count)
9037  {
9038  throw Exception("LocationNameMultiMap size = " + AnsiString(LocationNameMultiMap.size()) + " & Count = " + AnsiString(Count) +
9039  " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9040  }
9041 // check all entries in both vectors match entries in name multimap
9043 
9044  for(unsigned int x = 0; x < TrackVector.size(); x++)
9045  {
9046  if(TrackElementAt(1364, x).FixedNamedLocationElement)
9047  {
9048  SName = TrackElementAt(1365, x).LocationName;
9049  SNIt = FindNamedElementInLocationNameMultiMap(5, SName, TrackVector.begin() + x, ErrorString);
9050  if(ErrorString != "")
9051  {
9052  throw Exception(ErrorString + " in CheckLocationNameMultiMap for TrackVector check, caller = " + AnsiString(Caller));
9053  }
9054  if(SNIt->second != -1 - (int)x)
9055  {
9056  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9057  AnsiString(Caller));
9058  }
9059  }
9060  // check corresponding platform for all Timetable entries that aren't empty
9061  TName = TrackElementAt(1366, x).ActiveTrackElementName;
9062  TIMPair IMPair;
9063  bool FoundFlag = false;
9064  if(TName != "")
9065  {
9066  IMPair = GetVectorPositionsFromInactiveTrackMap(10, TrackElementAt(1367, x).HLoc, TrackElementAt(1368, x).VLoc, FoundFlag);
9067  if(FoundFlag)
9068  {
9069  if((InactiveTrackElementAt(17, IMPair.first).TrackType != Platform) && (InactiveTrackElementAt(18, IMPair.second).TrackType != Platform) &&
9071  {
9072  throw Exception("Track element with ActiveTrackElementName but no plat/named loc at H " + AnsiString(TrackElementAt(1369, x).HLoc) + " & V " +
9073  AnsiString(TrackElementAt(1370, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9074  }
9075  if((InactiveTrackElementAt(20, IMPair.first).LocationName != TName) && (InactiveTrackElementAt(21, IMPair.second).LocationName != TName))
9076  {
9077  throw Exception("Track element with ActiveTrackElementName " + TName + " but plat/named loc at H " + AnsiString(TrackElementAt(1371, x).HLoc) +
9078  " & V " + AnsiString(TrackElementAt(1372, x).VLoc) + " has different LocationName in CheckLocationNameMultiMap, caller = " +
9079  AnsiString(Caller));
9080  }
9081  }
9082  else
9083  {
9084  throw Exception("Track element with ActiveTrackElementName but no inactive element at H " + AnsiString(TrackElementAt(1373, x).HLoc) + " & V " +
9085  AnsiString(TrackElementAt(1374, x).VLoc) + " in CheckLocationNameMultiMap, caller = " + AnsiString(Caller));
9086  }
9087  }
9088  }
9089  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
9090  {
9091  if(InactiveTrackElementAt(147, x).FixedNamedLocationElement)
9092  {
9093  SName = InactiveTrackElementAt(148, x).LocationName;
9094  SNIt = FindNamedElementInLocationNameMultiMap(6, SName, InactiveTrackVector.begin() + x, ErrorString);
9095  if(ErrorString != "")
9096  {
9097  throw Exception(ErrorString + " in CheckLocationNameMultiMap for InactiveTrackVector check, caller = " + AnsiString(Caller));
9098  }
9099  if(SNIt->second != (int)x)
9100  {
9101  throw Exception("Elements different in name map & TrackVector in CheckLocationNameMultiMap for TrackVector check, caller = " +
9102  AnsiString(Caller));
9103  }
9104  }
9105  }
9106  Utilities->CallLogPop(585);
9107 }
9108 
9109 // ---------------------------------------------------------------------------
9110 
9112  AnsiString &ErrorString)
9113 {
9114 /*
9115  Searches the name map to check if the element pointed to by the TTrackVectorIterator has the name
9116  LocationName. If it finds it the pointer TLocationNameMultiMapIterator is returned. If it fails ErrorString
9117  is set to an appropriate text to allow the calling function to report the error. Otherwise it is set to "".
9118 */
9119  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindNamedElementInLocationNameMultiMap," + LocationName + "," +
9120  AnsiString(TrackElement->HLoc) + "," + AnsiString(TrackElement->VLoc) + "," + AnsiString(TrackElement->SpeedTag));
9121  ErrorString = "";
9122  bool FoundFlag = false;
9123  TLocationNameMultiMapIterator SNIterator;
9124  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
9125 
9126  if(SNRange.first == SNRange.second)
9127  {
9128  ErrorString = "Error, Name " + LocationName + " not found in map";
9129  Utilities->CallLogPop(586);
9130  return(SNRange.first);
9131  }
9132  else
9133  {
9134  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
9135  {
9136  if(SNIterator->second < 0)
9137  {
9138  int TVPos = -1 - SNIterator->second;
9139  TTrackVectorIterator TVIt = TrackVector.begin() + TVPos;
9140  if(TVIt == TrackElement)
9141  {
9142  FoundFlag = true;
9143  Utilities->CallLogPop(587);
9144  return(SNIterator);
9145  }
9146  }
9147  else
9148  {
9149  int ITVPos = SNIterator->second;
9150  TTrackVectorIterator ITVIt = InactiveTrackVector.begin() + ITVPos;
9151  if(ITVIt == TrackElement)
9152  {
9153  FoundFlag = true;
9154  Utilities->CallLogPop(588);
9155  return(SNIterator);
9156  }
9157  }
9158  }
9159  }
9160  if(!FoundFlag)
9161  {
9162  ErrorString = "Error, Name " + LocationName + " found but not at required element";
9163  }
9164  Utilities->CallLogPop(589);
9165  return(SNIterator);
9166 }
9167 
9168 // ---------------------------------------------------------------------------
9169 
9170 void TTrack::ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
9171 {
9172 /*
9173  Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationNameMultiMapIterator
9174  from whatever it was before. Accepts null entries so that a formerly named element can have the name changed to "".
9175 */
9176  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ChangeLocationNameMultiMapEntry," + NewName);
9177  TLocationNameMultiMapEntry LocationNameEntry;
9178 
9179  LocationNameEntry.first = NewName;
9180  LocationNameEntry.second = SNIterator->second;
9181  LocationNameMultiMap.erase(SNIterator);
9182  LocationNameMultiMap.insert(LocationNameEntry);
9183  Utilities->CallLogPop(590);
9184 }
9185 
9186 // ---------------------------------------------------------------------------
9187 
9189 {
9190 // Takes an adjusted vector position value and returns a pointer to the relevant element. Can be in either vector.
9191  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetTrackVectorIteratorFromNamePosition," + AnsiString(Position));
9192  if(Position < 0) // footcrossing
9193  {
9194  int TruePos = -1 - Position;
9195  // new check at v0.2b
9196  if(TrackElementAt(817, TruePos).TrackType != FootCrossing)
9197  {
9198  throw Exception("Footbridge/underpass error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9199  }
9200  Utilities->CallLogPop(591);
9201  return (TrackVector.begin() + TruePos);
9202  }
9203  else
9204  {
9205  // new check at v0.2b
9206  if(!(InactiveTrackElementAt(99, Position).FixedNamedLocationElement))
9207  {
9208  throw Exception("Inactive element error in GetTrackVectorIteratorFromNamePosition, caller = " + AnsiString(Caller));
9209  }
9210  Utilities->CallLogPop(592);
9211  return (InactiveTrackVector.begin() + Position);
9212  }
9213 }
9214 
9215 // ---------------------------------------------------------------------------
9216 
9217 void TTrack::DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
9218 {
9219 /*
9220  After an element has been erased from the inactive track vector, all the later elements are moved down one. This function
9221  decrements the position values for all values above that of the erased element in both InactiveTrack2MultiMap and
9222  LocationNameMultiMap.
9223 */
9224  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInInactiveTrackAndNameMaps," + AnsiString(VecPos));
9225  TInactiveTrack2MultiMapIterator InactiveTrack2MultiMapIterator;
9226  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9227 
9228  if(!InactiveTrack2MultiMap.empty())
9229  {
9230  for(InactiveTrack2MultiMapIterator = InactiveTrack2MultiMap.begin(); InactiveTrack2MultiMapIterator != InactiveTrack2MultiMap.end();
9231  InactiveTrack2MultiMapIterator++)
9232  {
9233  if(InactiveTrack2MultiMapIterator->second > VecPos)
9234  {
9235  InactiveTrack2MultiMapIterator->second--;
9236  }
9237  // can't be == VecPos as that position erased
9238  }
9239  }
9240  if(!LocationNameMultiMap.empty())
9241  {
9242  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9243  LocationNameMultiMapIterator++)
9244  {
9245  if(LocationNameMultiMapIterator->second < 0)
9246  {
9247  continue; // deal with TrackVectors separately
9248  }
9249  if(LocationNameMultiMapIterator->second > (int)VecPos)
9250  {
9251  LocationNameMultiMapIterator->second--;
9252  }
9253  }
9254  }
9255  Utilities->CallLogPop(593);
9256 }
9257 
9258 // ---------------------------------------------------------------------------
9259 
9260 void TTrack::DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
9261 {
9262 /*
9263  After an element has been erased from the track vector, all the later elements are moved down one. This function
9264  decrements the position values for all values above that of the erased element in the gap elements, TrackMap and
9265  LocationNameMultiMap.
9266 */
9267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementValuesInGapsAndTrackAndNameMaps," + AnsiString(VecPos));
9268  TTrackMapIterator TrackMapIterator;
9269  TLocationNameMultiMapIterator LocationNameMultiMapIterator;
9270 
9271  if(!TrackMap.empty())
9272  {
9273  for(TrackMapIterator = TrackMap.begin(); TrackMapIterator != TrackMap.end(); TrackMapIterator++)
9274  {
9275  if(TrackMapIterator->second > VecPos)
9276  {
9277  TrackMapIterator->second--;
9278  }
9279  // can't be == VecPos as that position erased
9280  }
9281  }
9282  if(!LocationNameMultiMap.empty())
9283  {
9284  for(LocationNameMultiMapIterator = LocationNameMultiMap.begin(); LocationNameMultiMapIterator != LocationNameMultiMap.end();
9285  LocationNameMultiMapIterator++)
9286  {
9287  if(LocationNameMultiMapIterator->second >= 0)
9288  {
9289  continue; // deal with InactiveTrackVectors separately
9290  }
9291  // (-1-VecPos) VP 0 1 2 3 4 5 6 7
9292  // Val -1 -2 -3 -4 -5 -6 -7 -8
9293  if(LocationNameMultiMapIterator->second < -(int)(VecPos + 1))
9294  {
9295  LocationNameMultiMapIterator->second++;
9296  }
9297  }
9298  }
9299  for(unsigned int x = 0; x < TrackVector.size(); x++)
9300  {
9301  TTrackElement &TkEl = TrackElementAt(1375, x); // no need to check so use this to speed up
9302  if(TkEl.TrackType == GapJump)
9303  {
9304  // position 0 is the gap
9305  if(TkEl.Conn[0] == int(VecPos))
9306  {
9307  TkEl.Conn[0] = -1; // connected to a deleted gap
9308  continue;
9309  }
9310  if(TkEl.Conn[0] > int(VecPos))
9311  {
9312  TkEl.Conn[0]--;
9313  }
9314  if(TkEl.Conn[0] > -1) // don't use 'else' here, need to check the value whether changed or not
9315  {
9316  if(TrackElementAt(709, TkEl.Conn[0]).TrackType != GapJump)
9317  {
9318  TkEl.Conn[0] = -1;
9319  }
9320  }
9321  }
9322  }
9323  Utilities->CallLogPop(1433);
9324 }
9325 
9326 // ---------------------------------------------------------------------------
9327 
9329 /*
9330  Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector. Called after the
9331  track is linked as many of the vector positions are likely to change - called from RepositionAndMapTrack();
9332  after names are changed in EraseLocationAndActiveTrackElementNames; and after the name changes in EnterLocationName.
9333 */
9334 {
9335  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildLocationNameMultiMap");
9336  LocationNameMultiMap.clear();
9337  TLocationNameMultiMapEntry LocationNameEntry;
9338  TTrackElement TrackElement;
9339 
9340  for(unsigned int TVPos = 0; TVPos < TrackVector.size(); TVPos++)
9341  {
9342  TrackElement = TrackElementAt(1376, TVPos);
9343  if(TrackElement.FixedNamedLocationElement)
9344  {
9345  LocationNameEntry.first = TrackElement.LocationName;
9346  LocationNameEntry.second = -1 - TVPos; // adjusted for footcrossings
9347  LocationNameMultiMap.insert(LocationNameEntry);
9348  }
9349  }
9350 
9351  for(unsigned int ITVPos = 0; ITVPos < InactiveTrackVector.size(); ITVPos++)
9352  {
9353  TrackElement = InactiveTrackElementAt(149, ITVPos);
9354  if(TrackElement.FixedNamedLocationElement)
9355  {
9356  LocationNameEntry.first = TrackElement.LocationName;
9357  LocationNameEntry.second = ITVPos;
9358  LocationNameMultiMap.insert(LocationNameEntry);
9359  }
9360  }
9361  Utilities->CallLogPop(594);
9362 }
9363 
9364 // ---------------------------------------------------------------------------
9365 
9367 // Return true if there is a named location present in the railway
9368 // ignores lone footcrossings, can't name these on their own & track won't link if there are any
9369 {
9370  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NonFootCrossingNamedLocationExists");
9371  TTrackVectorIterator ITVI;
9372 
9373  if(InactiveTrackVector.empty())
9374  {
9375  Utilities->CallLogPop(1343);
9376  return(false);
9377  }
9378  for(ITVI = InactiveTrackVector.begin(); ITVI != InactiveTrackVector.end(); ITVI++)
9379  {
9380  if((ITVI->TrackType == Platform) || (ITVI->TrackType == NamedNonStationLocation) || (ITVI->TrackType == Concourse))
9381  {
9382  Utilities->CallLogPop(1404);
9383  return(true);
9384  }
9385  }
9386  Utilities->CallLogPop(1344);
9387  return(false);
9388 }
9389 
9390 // ---------------------------------------------------------------------------
9391 
9393 /*
9394  Work through all elements in TrackVector setting all lengths & speed limits to default values - including both tracks for 2-track elements
9395 */
9396 {
9397  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllDefaultLengthsAndSpeedLimits");
9398 // ResetDistanceElements(6);
9399  for(unsigned int x = 0; x < TrackVector.size(); x++)
9400  {
9401  TTrackElement &TE = TrackElementAt(718, x);
9404  if((TE.TrackType == Points) || (TE.TrackType == Crossover) || (TE.TrackType == Bridge))
9405  {
9408  }
9409  }
9410 /* old function
9411  if((TrackElementAt(, x).TrackType == Points) || (TrackElementAt(, x).TrackType == Crossover) || (TrackElementAt(, x).TrackType == Bridge))
9412  {
9413  SetOneDefaultTrackLength(2, TrackElementAt(, x), 0);
9414  SetOneDefaultTrackLength(3, TrackElementAt(, x), 2);
9415  }
9416  else
9417  {
9418  SetOneDefaultTrackLength(4, TrackElementAt(, x), 0);
9419  }
9420  }
9421 */
9422  Utilities->CallLogPop(617);
9423 }
9424 
9425 // ---------------------------------------------------------------------------
9426 
9427 void TTrack::LengthMarker(int Caller, TDisplay *Disp)
9428 // Examine all elements in the TrackVector and if have a valid length mark the relevant track using MarkOneLength.
9429 {
9430  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LengthMarker");
9431  for(unsigned int x = 0; x < TrackVector.size(); x++)
9432  {
9433  TTrackElement TempElement = TrackElementAt(1377, x);
9434  if(TempElement.Length01 > -1)
9435  {
9436  MarkOneLength(1, TempElement, true, Disp); // need Length01 test in case there are erase elements (but shouldn't be after LinkTrack)
9437  }
9438  if(TempElement.Length23 > -1)
9439  {
9440  MarkOneLength(2, TempElement, false, Disp);
9441  }
9442  }
9443  Disp->Update();
9444  Utilities->CallLogPop(618);
9445 }
9446 
9447 // ---------------------------------------------------------------------------
9448 
9449 void TTrack::MarkOneLength(int Caller, TTrackElement TrackElement, bool FirstTrack, TDisplay *Disp)
9450 /*
9451  Rule: Only marked if different in any way from the default values - length 100m and speed limit 200km/h
9452  First check using IsElementTrackDefaultLength whether the relevant track is already set to the default values, and if so
9453  return as nothing further to do. Otherwise pick up the appropriate bitmap (using the AutoSigRouteGraphicsPtr bitmaps)
9454  using the same technique as in TPrefDirElement::EntryExitNumber() & *TPrefDirElement::GetPrefDirGraphicPtr(), for the relevant
9455  track as indicated by FirstTrack (true for track01 & false for track23).
9456 */
9457 {
9458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkOneLength," + TrackElement.LogTrack(8) + "," +
9459  AnsiString((short)FirstTrack));
9460  bool LengthDifferent = false, SpeedDifferent = false;
9461 
9462  if(IsElementDefaultLength(1, TrackElement, FirstTrack, LengthDifferent, SpeedDifferent))
9463  {
9464  Utilities->CallLogPop(619);
9465  return;
9466  }
9467  int EXArray[16][2] =
9468  {{4, 6}, {2, 8}, // horizontal & vertical
9469  {2, 4}, {6, 2}, {8, 6}, {4, 8}, // sharp curves
9470  {1, 6}, {3, 8}, {9, 4}, {7, 2}, {1, 8}, {3, 4}, {9, 2}, {7, 6}, // loose curves
9471  {1, 9}, {3, 7}}; // forward & reverse diagonals
9472 
9473  int Index = -1, BrNum = -1, GrNum = -1, InLink, OutLink;
9474  Graphics::TBitmap *Bitmap;
9475 
9476  if(FirstTrack)
9477  {
9478  InLink = TrackElement.Link[0];
9479  OutLink = TrackElement.Link[1];
9480  }
9481  else
9482  {
9483  InLink = TrackElement.Link[2];
9484  OutLink = TrackElement.Link[3];
9485  }
9486  for(int x = 0; x < 16; x++)
9487  {
9488  if((InLink == EXArray[x][0] && OutLink == EXArray[x][1]) || (InLink == EXArray[x][1] && OutLink == EXArray[x][0]))
9489  {
9490  Index = x;
9491  }
9492  }
9493  if(Index == -1)
9494  {
9495  throw Exception("Error, failed to find Index in TTrack::MarkOneLength");
9496  }
9497 /* The order for bridge entries & exits is as below. Note that there are 3 of each type,
9498  the graphic for each of which is different because of the shape of the overbridge. The basic
9499  entry/exit value is computed above, and this used to select only from elements with that entry/exit
9500  value that is an underbridge, i.e overbridges ignored as the normal graphic is OK for them.
9501  int BrEXArray[24][2] = {
9502  {4,6},{2,8},{1,9},{3,7},
9503  {1,9},{3,7},{1,9},{3,7},
9504  {2,8},{4,6},{2,8},{4,6}
9505 */
9506  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9507  {
9508  if(Index == 1)
9509  {
9510  if(TrackElement.SpeedTag == 49)
9511  {
9512  BrNum = 1 + 16;
9513  }
9514  else if(TrackElement.SpeedTag == 54)
9515  {
9516  BrNum = 8 + 16;
9517  }
9518  else if(TrackElement.SpeedTag == 55)
9519  {
9520  BrNum = 10 + 16;
9521  }
9522  }
9523  else if(Index == 0)
9524  {
9525  if(TrackElement.SpeedTag == 48)
9526  {
9527  BrNum = 0 + 16;
9528  }
9529  else if(TrackElement.SpeedTag == 58)
9530  {
9531  BrNum = 11 + 16;
9532  }
9533  else if(TrackElement.SpeedTag == 59)
9534  {
9535  BrNum = 9 + 16;
9536  }
9537  }
9538  else if(Index == 14)
9539  {
9540  if(TrackElement.SpeedTag == 50)
9541  {
9542  BrNum = 2 + 16;
9543  }
9544  else if(TrackElement.SpeedTag == 52)
9545  {
9546  BrNum = 4 + 16;
9547  }
9548  else if(TrackElement.SpeedTag == 57)
9549  {
9550  BrNum = 6 + 16;
9551  }
9552  }
9553  else if(Index == 15)
9554  {
9555  if(TrackElement.SpeedTag == 51)
9556  {
9557  BrNum = 3 + 16;
9558  }
9559  else if(TrackElement.SpeedTag == 53)
9560  {
9561  BrNum = 7 + 16;
9562  }
9563  else if(TrackElement.SpeedTag == 56)
9564  {
9565  BrNum = 5 + 16;
9566  }
9567  }
9568  }
9569  if(!FirstTrack && (TrackElement.TrackType == Bridge))
9570  {
9571  GrNum = BrNum;
9572  }
9573  else
9574  {
9575  GrNum = Index;
9576  }
9577  if(LengthDifferent && SpeedDifferent) // blue - use autosig graphics
9578  {
9579  if(GrNum > 15) // underbridge
9580  {
9581  Bitmap = RailGraphics->BridgeRouteAutoSigsGraphicsPtr[GrNum - 16];
9582  }
9583  else
9584  {
9585  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[GrNum];
9586  }
9587  if(TrackElement.SpeedTag == 64)
9588  {
9589  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9590  }
9591  if(TrackElement.SpeedTag == 65)
9592  {
9594  }
9595  if(TrackElement.SpeedTag == 66)
9596  {
9598  }
9599  if(TrackElement.SpeedTag == 67)
9600  {
9602  }
9603  if(TrackElement.SpeedTag == 80)
9604  {
9605  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[20]; // intercept continuations to show the dots
9606  }
9607  if(TrackElement.SpeedTag == 81)
9608  {
9610  }
9611  if(TrackElement.SpeedTag == 82)
9612  {
9614  }
9615  if(TrackElement.SpeedTag == 83)
9616  {
9618  }
9619  if(TrackElement.SpeedTag == 84)
9620  {
9622  }
9623  if(TrackElement.SpeedTag == 85)
9624  {
9626  }
9627  if(TrackElement.SpeedTag == 86)
9628  {
9630  }
9631  if(TrackElement.SpeedTag == 87)
9632  {
9634  }
9635  if(TrackElement.SpeedTag == 129)
9636  {
9637  Bitmap = RailGraphics->LinkRouteAutoSigsGraphicsPtr[28]; // intercept under footbridges
9638  }
9639  if(TrackElement.SpeedTag == 130)
9640  {
9642  }
9643  }
9644 
9645  else if(LengthDifferent && !SpeedDifferent) // green - use pref sig graphics
9646  {
9647  if(GrNum > 15) // underbridge
9648  {
9649  Bitmap = RailGraphics->BridgeSigRouteGraphicsPtr[GrNum - 16];
9650  }
9651  else
9652  {
9653  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[GrNum];
9654  }
9655  if(TrackElement.SpeedTag == 64)
9656  {
9657  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9658  }
9659  if(TrackElement.SpeedTag == 65)
9660  {
9661  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[17];
9662  }
9663  if(TrackElement.SpeedTag == 66)
9664  {
9665  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[18];
9666  }
9667  if(TrackElement.SpeedTag == 67)
9668  {
9669  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[19];
9670  }
9671  if(TrackElement.SpeedTag == 80)
9672  {
9673  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9674  }
9675  if(TrackElement.SpeedTag == 81)
9676  {
9677  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[21];
9678  }
9679  if(TrackElement.SpeedTag == 82)
9680  {
9681  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[22];
9682  }
9683  if(TrackElement.SpeedTag == 83)
9684  {
9685  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[23];
9686  }
9687  if(TrackElement.SpeedTag == 84)
9688  {
9689  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[24];
9690  }
9691  if(TrackElement.SpeedTag == 85)
9692  {
9693  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[25];
9694  }
9695  if(TrackElement.SpeedTag == 86)
9696  {
9697  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[26];
9698  }
9699  if(TrackElement.SpeedTag == 87)
9700  {
9701  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[27];
9702  }
9703  if(TrackElement.SpeedTag == 129)
9704  {
9705  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[28]; // intercept under footbridges
9706  }
9707  if(TrackElement.SpeedTag == 130)
9708  {
9709  Bitmap = RailGraphics->LinkSigRouteGraphicsPtr[29];
9710  }
9711  }
9712 
9713  else // SpeedDifferent only: red - use non sig graphics
9714  {
9715  if(GrNum > 15) // underbridge
9716  {
9717  Bitmap = RailGraphics->BridgeNonSigRouteGraphicsPtr[GrNum - 16];
9718  }
9719  else
9720  {
9721  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[GrNum];
9722  }
9723  if(TrackElement.SpeedTag == 64)
9724  {
9725  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[16]; // intercept diagonal buffers to show the buffer
9726  }
9727  if(TrackElement.SpeedTag == 65)
9728  {
9730  }
9731  if(TrackElement.SpeedTag == 66)
9732  {
9734  }
9735  if(TrackElement.SpeedTag == 67)
9736  {
9738  }
9739  if(TrackElement.SpeedTag == 80)
9740  {
9741  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[20]; // intercept continuations to show the dots
9742  }
9743  if(TrackElement.SpeedTag == 81)
9744  {
9746  }
9747  if(TrackElement.SpeedTag == 82)
9748  {
9750  }
9751  if(TrackElement.SpeedTag == 83)
9752  {
9754  }
9755  if(TrackElement.SpeedTag == 84)
9756  {
9758  }
9759  if(TrackElement.SpeedTag == 85)
9760  {
9762  }
9763  if(TrackElement.SpeedTag == 86)
9764  {
9766  }
9767  if(TrackElement.SpeedTag == 87)
9768  {
9770  }
9771  if(TrackElement.SpeedTag == 129)
9772  {
9773  Bitmap = RailGraphics->LinkNonSigRouteGraphicsPtr[28]; // intercept under footbridges
9774  }
9775  if(TrackElement.SpeedTag == 130)
9776  {
9778  }
9779  }
9780  Disp->PlotOutput(67, TrackElement.HLoc * 16, TrackElement.VLoc * 16, Bitmap);
9781  Utilities->CallLogPop(620);
9782 }
9783 
9784 // ---------------------------------------------------------------------------
9785 
9786 bool TTrack::IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
9787 /* FirstTrack = LinkPos's 0 & 1
9788  Examine track within TrackElement & check whether it has the default length and speed limit, return true if so
9789 */
9790 {
9791  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementTrackDefaultLength," + TrackElement.LogTrack(10) + "," +
9792  AnsiString((short)FirstTrack));
9793  LengthDifferent = false;
9794  SpeedDifferent = false;
9795  if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && FirstTrack)
9796  {
9797  if(TrackElement.Length01 != DefaultTrackLength)
9798  {
9799  LengthDifferent = true;
9800  }
9801  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9802  {
9803  SpeedDifferent = true;
9804  }
9805  if(LengthDifferent || SpeedDifferent)
9806  {
9807  Utilities->CallLogPop(625);
9808  return(false);
9809  }
9810  Utilities->CallLogPop(626);
9811  return(true);
9812  }
9813 
9814  else if(((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Points) || (TrackElement.TrackType == Crossover)) && !FirstTrack)
9815  {
9816  if(TrackElement.Length23 != DefaultTrackLength)
9817  {
9818  LengthDifferent = true;
9819  }
9820  if(TrackElement.SpeedLimit23 != DefaultTrackSpeedLimit)
9821  {
9822  SpeedDifferent = true;
9823  }
9824  if(LengthDifferent || SpeedDifferent)
9825  {
9826  Utilities->CallLogPop(627);
9827  return(false);
9828  }
9829  Utilities->CallLogPop(628);
9830  return(true);
9831  }
9832 
9833  else // any other 1 track element, including platforms being present
9834  {
9835  if(TrackElement.Length01 != DefaultTrackLength)
9836  {
9837  LengthDifferent = true;
9838  }
9839  if(TrackElement.SpeedLimit01 != DefaultTrackSpeedLimit)
9840  {
9841  SpeedDifferent = true;
9842  }
9843  if(LengthDifferent || SpeedDifferent)
9844  {
9845  Utilities->CallLogPop(629);
9846  return(false);
9847  }
9848  Utilities->CallLogPop(630);
9849  return(true);
9850  }
9851 }
9852 
9853 // ---------------------------------------------------------------------------
9854 
9855 bool TTrack::IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9856 // Check whether there is a platform or NamedNonStationLocation present at HLoc & VLoc, return true if so
9857 {
9858  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsPlatformOrNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9859  AnsiString(VLoc));
9860  bool FoundFlag;
9861  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(11, HLoc, VLoc, FoundFlag);
9862 
9863  if(!FoundFlag)
9864  {
9865  Utilities->CallLogPop(633);
9866  return(false);
9867  }
9868  if((InactiveTrackElementAt(42, IMPair.first).TrackType == Platform) || (InactiveTrackElementAt(91, IMPair.first).TrackType == NamedNonStationLocation))
9869  {
9870  Utilities->CallLogPop(634);
9871  return(true); // only need to check first since if second is a platform the the first must be too
9872  }
9873  else
9874  {
9875  Utilities->CallLogPop(635);
9876  return(false);
9877  }
9878 }
9879 
9880 // ---------------------------------------------------------------------------
9881 
9882 bool TTrack::IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
9883 // Check whether there is a NamedNonStationLocation present at HLoc & VLoc, return true if so
9884 {
9885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsNamedNonStationLocationPresent," + AnsiString(HLoc) + "," +
9886  AnsiString(VLoc));
9887  bool FoundFlag;
9888  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(12, HLoc, VLoc, FoundFlag);
9889 
9890  if(!FoundFlag)
9891  {
9892  Utilities->CallLogPop(636);
9893  return(false);
9894  }
9896  {
9897  Utilities->CallLogPop(637);
9898  return(true); // only need to check first since only one used for NamedNonStationLocations
9899  }
9900  else
9901  {
9902  Utilities->CallLogPop(638);
9903  return(false);
9904  }
9905 }
9906 
9907 // ---------------------------------------------------------------------------
9908 
9910 /* Called when trying to link track and when a name changed when track already linked. Examines all track elements that
9911  have ActiveTrackElementName set, sums the number of consecutive elements with the same name, and sets the EntryLink values for
9912  the front of train stop points for each direction.
9913  For stations (not non-station named locations) of length n, where n > 1, stop element is [floor((n+1)/2) + 1] from each
9914  end (unless buffers at one or both ends in which case stop points are the end elements).
9915  Note that for a single element the stop point is the element itself (formula doesn't apply).
9916  During the function the StationEntryStopLink values are set to 5 if not used, so no need to keep
9917  repeating the procedure for every element. At the end all unused values are returned to -1.
9918  For NamedNonStationLocations the stop points are at the end elements to allow trains to stack up.
9919 */
9920 {
9921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetStationEntryStopLinkPosses");
9922  TTrackElement TempElement, StartElement;
9923  AnsiString TempName;
9924  int VecPos, StartVecPos, Count, EntryPos, StartEntryPos, ForwardNumber, ReverseNumber;
9925  bool ForwardSet, ReverseSet;
9926 
9927  for(unsigned int x = 0; x < TrackVector.size(); x++)
9928  {
9931  }
9932  for(unsigned int x = 0; x < TrackVector.size(); x++)
9933  {
9934  ForwardSet = false;
9935  ReverseSet = false;
9936  TempElement = TrackElementAt(1380, x);
9937  VecPos = x;
9938  if((TempElement.ActiveTrackElementName != "") && (TempElement.StationEntryStopLinkPos1 == -1))
9939  // 2nd condition incl so don't re-examine elements with stop links set to 5
9940  {
9941  TempName = TempElement.ActiveTrackElementName;
9942  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(44, TempElement.Conn[0]).ActiveTrackElementName == TempName) &&
9943  (TrackElementAt(45, TempElement.Conn[1]).ActiveTrackElementName == TempName))
9944  // an element linked at both ends where both links are also named elements
9945  // only Conn[0] & [1] relevant for ActiveTrackElementName elements (only 2-track named element is points, and only straight track relevant & this has 0 & 1 as entry/exit positions)
9946  {
9947  continue; // looking for an end element so skip this one
9948  }
9949  else // reached one end
9950  {
9951  if((TempElement.Conn[0] > -1) && (TempElement.Conn[1] > -1) && (TrackElementAt(46, TempElement.Conn[0]).ActiveTrackElementName != TempName) &&
9952  (TrackElementAt(47, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9953  // single named element linked at both ends
9954  {
9955  TrackElementAt(48, VecPos).StationEntryStopLinkPos1 = 0;
9956  TrackElementAt(49, VecPos).StationEntryStopLinkPos2 = 1;
9957  continue;
9958  }
9959  else if((TempElement.TrackType == Buffers) && (TrackElementAt(618, TempElement.Conn[1]).ActiveTrackElementName != TempName))
9960  // single named buffer element (LinkPos 1 is the non-buffer end)
9961  {
9962  TrackElementAt(619, VecPos).StationEntryStopLinkPos1 = 0;
9963  TrackElementAt(620, VecPos).StationEntryStopLinkPos2 = 1;
9964  continue;
9965  }
9966  else
9967  // Note: only interested in connection positions 0 & 1 since all named elements are single track except points,
9968  // and platforms always on straight (conns 0 & 1) section of points
9969  {
9970  for(int y = 0; y < 2; y++)
9971  {
9972  int Dir = y; // Dir is the ExitPos of the element, towards the rest of the named elements
9973  // check for buffers at both ends - no need, function below now covers buffers at one & both ends
9974 /* TTrackElement Temp1 = TempElement;
9975  ***********New section, compiles but not checked - does bit below need to be else if?
9976  if((Temp1.TrackType == Buffers) && (Temp1.GetConfig(Dir) != End))
9977  {
9978  //search along Dir direction until find other end, skip if Dir facing buffer end
9979  int NewDir = Dir;
9980  int NewVecPos;
9981  while((Temp1.Conn[NewDir] > -1) && (TrackElementAt(598, Temp1.Conn[NewDir]).ActiveTrackElementName == TempName))
9982  {
9983  NewVecPos = Temp1.Conn[NewDir];
9984  NewDir = Track->GetNonPointsOppositeLinkPos(Temp1.ConnLinkPos[NewDir]);
9985  Temp1 = TrackElementAt(601, NewVecPos);
9986  }
9987  if((Temp1.Conn[NewDir] == -1) && (Temp1.TrackType == Buffers))
9988  {
9989  TrackElementAt(599, VecPos).StationEntryStopLinkPos1 = Dir;//EntryPos for train coming from other end is Dir
9990  TrackElementAt(600, NewVecPos).StationEntryStopLinkPos2 = 1 - NewDir;//For train moving in same direction as search direction its EntryPos == 1 - NewDir since NewDir is the ExitPos
9991  }
9992  }
9993  ***************
9994 */
9995  // end may be linked at both ends but only one link named, or buffer with linked element named
9996  // if a buffer then the named linkpos has to be 1
9997  // already dealt with all types of single element so at least 2 linked named element
9998  if(((TempElement.Conn[Dir] > -1) && (TempElement.Conn[1 - Dir] > -1) && (TrackElementAt(50,
9999  TempElement.Conn[1 - Dir]).ActiveTrackElementName != TempName)) || ((TempElement.TrackType == Buffers) && (Dir == 1)))
10000  {
10001  StartElement = TempElement;
10002  StartVecPos = VecPos;
10003  TrackElementAt(51, VecPos).StationEntryStopLinkPos1 = 5; // set to 5 to stop re-examination in later searches, all set back at end
10004  TrackElementAt(52, VecPos).StationEntryStopLinkPos2 = 5;
10005  EntryPos = 1 - Dir;
10006  StartEntryPos = 1 - Dir;
10007  Count = 1;
10008  // work along named elements until find the other end
10009  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(53,
10010  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName))
10011  // at end of 'while' Count = length (in elements) of platform/nonstationloc, VecPos = vector number of far end
10012  // which is the last named element that is track-linked to the rest of the location, it may be a buffer
10013  // all stop link pos's are set to 5
10014  {
10015  VecPos = TempElement.Conn[1 - EntryPos];
10016  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10017  TempElement = TrackElementAt(54, TempElement.Conn[1 - EntryPos]);
10018  EntryPos = TempEntryPos;
10019  Count++;
10020  TrackElementAt(55, VecPos).StationEntryStopLinkPos1 = 5;
10021  TrackElementAt(56, VecPos).StationEntryStopLinkPos2 = 5;
10022  }
10023  // here when reached other end, maybe buffers, continuation or last named linked element
10024  if(TrackElementAt(57, VecPos).TrackType == Buffers)
10025  // terminal station, set end elements as stop elements
10026  {
10027  TrackElementAt(58, VecPos).StationEntryStopLinkPos1 = EntryPos;
10028  TrackElementAt(59, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos; // for train leaving
10029  continue;
10030  }
10031  if(TrackElementAt(60, StartVecPos).TrackType == Buffers) // best not to use 'else if' as both ends could be buffers!
10032  // terminal station, set end elements as stop elements
10033  {
10034  TrackElementAt(61, VecPos).StationEntryStopLinkPos1 = EntryPos;
10035  TrackElementAt(62, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10036  continue;
10037  }
10038  if(IsNamedNonStationLocationPresent(1, TrackElementAt(63, StartVecPos).HLoc, TrackElementAt(64, StartVecPos).VLoc))
10039  // NonStationLocation so set end elements as stop elements
10040  {
10041  TrackElementAt(65, VecPos).StationEntryStopLinkPos1 = EntryPos;
10042  TrackElementAt(66, StartVecPos).StationEntryStopLinkPos2 = 1 - StartEntryPos;
10043  continue;
10044  }
10045  // now Count == length of platform, can calculate StationEntryStopLinkPos values and the elements to which they apply
10046  ForwardNumber = ((Count + 1) / 2) + 1;
10047  ReverseNumber = (Count - ForwardNumber) + 1;
10048  Count = 1; // starting value
10049  EntryPos = 1 - Dir;
10050  TempElement = StartElement;
10051  VecPos = StartVecPos;
10052  if(Count == ForwardNumber)
10053  {
10054  TrackElementAt(67, VecPos).StationEntryStopLinkPos1 = EntryPos;
10055  ForwardSet = true;
10056  }
10057  if(Count == ReverseNumber) // don't use 'else' as may both be at same element
10058  {
10059  TrackElementAt(68, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10060  ReverseSet = true;
10061  }
10062  while((TempElement.Conn[1 - EntryPos] > -1) && (TrackElementAt(69,
10063  TempElement.Conn[1 - EntryPos]).ActiveTrackElementName == TempName) && (!ForwardSet || !ReverseSet))
10064  {
10065  VecPos = TempElement.Conn[1 - EntryPos];
10066  int TempEntryPos = TempElement.ConnLinkPos[1 - EntryPos];
10067  TempElement = TrackElementAt(70, TempElement.Conn[1 - EntryPos]);
10068  EntryPos = TempEntryPos;
10069  Count++;
10070  if(Count == ForwardNumber)
10071  {
10072  TrackElementAt(71, VecPos).StationEntryStopLinkPos1 = EntryPos;
10073  ForwardSet = true;
10074  }
10075  if(Count == ReverseNumber)
10076  {
10077  TrackElementAt(72, VecPos).StationEntryStopLinkPos2 = 1 - EntryPos;
10078  ReverseSet = true;
10079  }
10080  }
10081  }
10082  }
10083  }
10084  }
10085  }
10086  }
10087  for(unsigned int x = 0; x < TrackVector.size(); x++)
10088  {
10089  if(TrackElementAt(1381, x).StationEntryStopLinkPos1 == 5)
10090  {
10092  }
10093  if(TrackElementAt(1383, x).StationEntryStopLinkPos2 == 5)
10094  {
10096  }
10097  }
10098  Utilities->CallLogPop(639);
10099 }
10100 
10101 // ---------------------------------------------------------------------------
10102 
10103 void TTrack::PlotSmallRailway(int Caller, TDisplay *Disp)
10104 {
10105  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRailway");
10106  TTrackElement Next;
10107 
10109  while(ReturnNextInactiveTrackElement(1, Next))
10110  {
10111  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10112  {
10113  if(((Next.TrackType == Platform) || (Next.TrackType == Concourse) || (Next.TrackType == NamedNonStationLocation)) && (Next.LocationName == ""))
10114  // need striped graphics
10115  {
10116  if(Next.SpeedTag == 76)
10117  {
10118  Disp->PlotSmallOutput(11, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm76striped);
10119  }
10120  else if(Next.SpeedTag == 77)
10121  {
10122  Disp->PlotSmallOutput(12, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm77striped);
10123  }
10124  else if(Next.SpeedTag == 78)
10125  {
10126  Disp->PlotSmallOutput(13, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm78striped);
10127  }
10128  else if(Next.SpeedTag == 79)
10129  {
10130  Disp->PlotSmallOutput(14, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm79striped);
10131  }
10132  else if(Next.SpeedTag == 96)
10133  {
10134  Disp->PlotSmallOutput(15, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm96striped);
10135  }
10136  else if(Next.SpeedTag == 131)
10137  {
10138  Disp->PlotSmallOutput(16, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm131striped);
10139  }
10140  }
10141  else
10142  {
10143  Disp->PlotSmallOutput(17, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10144  }
10145  }
10146  }
10147 
10148  NextTrackElementPtr = TrackVector.begin();
10149  while(ReturnNextTrackElement(1, Next))
10150  {
10151  if(Next.SmallGraphicPtr != 0) // don't think this should ever be 0 but leave as a safeguard
10152  {
10153  if((Next.TrackType == FootCrossing) && (Next.LocationName == "")) // need striped graphics, use sm129 & 130 for 145 & 146
10154  {
10155  if((Next.SpeedTag == 129) || (Next.SpeedTag == 145))
10156  {
10157  Disp->PlotSmallOutput(18, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm129striped);
10158  }
10159  else if((Next.SpeedTag == 130) || (Next.SpeedTag == 146))
10160  {
10161  Disp->PlotSmallOutput(19, Next.HLoc * 4, (Next.VLoc * 4), RailGraphics->sm130striped);
10162  }
10163  }
10164  else
10165  {
10166  Disp->PlotSmallOutput(20, Next.HLoc * 4, (Next.VLoc * 4), Next.SmallGraphicPtr);
10167  }
10168  }
10169  }
10170  Disp->Update();
10171  Utilities->CallLogPop(640);
10172 }
10173 
10174 // ---------------------------------------------------------------------------
10175 
10176 void TTrack::PlotSmallRedGap(int Caller)
10177 {
10178  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlotSmallRedGap");
10180  Utilities->CallLogPop(1346);
10181 }
10182 
10183 // ---------------------------------------------------------------------------
10184 
10185 void TTrack::TrackClear(int Caller)
10186 {
10187  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackClear");
10188  TrackVector.clear();
10189  InactiveTrackVector.clear();
10190  TrackMap.clear();
10192  if(TextHandler->TextVector.size() == 0)
10193  {
10194  Display->DisplayOffsetH = 0;
10195  Display->DisplayOffsetV = 0;
10202  HLocMin = 2000000000;
10203  HLocMax = -2000000000;
10204  VLocMin = 2000000000;
10205  VLocMax = -2000000000;
10206  }
10207  else
10208  {
10209  CalcHLocMinEtc(4);
10210  }
10211  Utilities->CallLogPop(1347);
10212 }
10213 
10214 // ---------------------------------------------------------------------------
10215 
10216 void TTrack::CalcHLocMinEtc(int Caller)
10217 {
10218  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcHLocMinEtc");
10219  HLocMin = 2000000000;
10220  VLocMin = 2000000000;
10221  HLocMax = -2000000000;
10222  VLocMax = -2000000000;
10223  for(unsigned int x = 0; x < TrackVector.size(); x++) // check all elements in turn
10224  {
10225  if(TrackElementAt(1385, x).SpeedTag == 0)
10226  {
10227  continue; // skip erase elements or would interfere with Min & Max values
10228  }
10229  if(TrackElementAt(1386, x).HLoc - 1 < HLocMin)
10230  {
10231  HLocMin = TrackElementAt(1387, x).HLoc - 1; // add one all round
10232  }
10233  if(TrackElementAt(1388, x).HLoc + 1 > HLocMax)
10234  {
10235  HLocMax = TrackElementAt(1389, x).HLoc + 1;
10236  }
10237  if(TrackElementAt(1390, x).VLoc - 1 < VLocMin)
10238  {
10239  VLocMin = TrackElementAt(1391, x).VLoc - 1;
10240  }
10241  if(TrackElementAt(1392, x).VLoc + 1 > VLocMax)
10242  {
10243  VLocMax = TrackElementAt(1393, x).VLoc + 1;
10244  }
10245  }
10246  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++) // check all elements in turn
10247  {
10248  if(InactiveTrackElementAt(150, x).SpeedTag == 0)
10249  {
10250  continue; // shouldn't be any inactive erase elements but include anyway
10251  }
10252  if(InactiveTrackElementAt(151, x).HLoc - 1 < HLocMin)
10253  {
10254  HLocMin = InactiveTrackElementAt(152, x).HLoc - 1; // add one all round
10255  }
10256  if(InactiveTrackElementAt(153, x).HLoc + 1 > HLocMax)
10257  {
10258  HLocMax = InactiveTrackElementAt(162, x).HLoc + 1;
10259  }
10260  if(InactiveTrackElementAt(154, x).VLoc - 1 < VLocMin)
10261  {
10262  VLocMin = InactiveTrackElementAt(155, x).VLoc - 1;
10263  }
10264  if(InactiveTrackElementAt(156, x).VLoc + 1 > VLocMax)
10265  {
10266  VLocMax = InactiveTrackElementAt(157, x).VLoc + 1;
10267  }
10268  }
10269  for(unsigned int x = 0; x < TextHandler->TextVectorSize(10); x++) // check all elements in turn
10270  {
10271 /* Removed at v2.2.0: It isn't needed because null names aren't entered into vector, and in any case if were then
10272  will fail as x will exceed the maximum value
10273  if(TextHandler->TextPtrAt(, x)->TextString == "")
10274  {
10275  TextHandler->TextErase(, TextHandler->TextPtrAt(35, x)->HPos, TextHandler->TextPtrAt(36, x)->VPos);
10276  }
10277 */
10278  int TextH = TextHandler->TextPtrAt(0, x)->HPos, TextV = TextHandler->TextPtrAt(1, x)->VPos;
10279  if((TextH / 16) - 1 < HLocMin)
10280  {
10281  HLocMin = (TextH / 16) - 1; // integer division will truncate so subtract 1 to ensure include the start
10282  }
10283  if((TextH / 16) + 1 > HLocMax)
10284  {
10285  HLocMax = (TextH / 16) + 1; // integer division will truncate so add 1 to ensure include the start
10286  }
10287  if((TextV / 16) - 1 < VLocMin)
10288  {
10289  VLocMin = (TextV / 16) - 1;
10290  }
10291  if((TextV / 16) + 1 > VLocMax)
10292  {
10293  VLocMax = (TextV / 16) + 1;
10294  }
10295  }
10296  for(unsigned int x = 0; x < UserGraphicVector.size(); x++) // added at v2.4.0
10297  {
10298  if((UserGraphicVectorAt(5, x).HPos / 16) - 1 < HLocMin)
10299  {
10300  HLocMin = (UserGraphicVectorAt(6, x).HPos / 16) - 1; // add one all round
10301  }
10302  if(((UserGraphicVectorAt(7, x).HPos + UserGraphicVectorAt(8, x).Width) / 16) + 1 > HLocMax)
10303  {
10304  HLocMax = ((UserGraphicVectorAt(9, x).HPos + UserGraphicVectorAt(10, x).Width) / 16) + 1;
10305  }
10306  if((UserGraphicVectorAt(11, x).VPos / 16) - 1 < VLocMin)
10307  {
10308  VLocMin = (UserGraphicVectorAt(12, x).VPos / 16) - 1;
10309  }
10310  if(((UserGraphicVectorAt(13, x).VPos + UserGraphicVectorAt(14, x).Height) / 16) + 1 > VLocMax)
10311  {
10312  VLocMax = ((UserGraphicVectorAt(15, x).VPos + UserGraphicVectorAt(16, x).Height) / 16) + 1;
10313  }
10314  }
10315 
10316  Utilities->CallLogPop(641);
10317 }
10318 
10319 // ---------------------------------------------------------------------------
10320 
10321 void TTrack::UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos,
10322  bool &UserGraphicFoundFlag)
10323 {
10324  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicMove," + AnsiString(HPosInput) + "," + AnsiString(VPosInput));
10325  TUserGraphicVector::iterator UserGraphicPtr;
10326 
10327  UserGraphicFoundFlag = false;
10328  if(!UserGraphicVector.empty())
10329  {
10330  int x = UserGraphicVector.size();
10331  for(UserGraphicPtr = (UserGraphicVector.end() - 1); UserGraphicPtr >= UserGraphicVector.begin(); UserGraphicPtr--)
10332  {
10333  x--;
10334  if((HPosInput >= (*UserGraphicPtr).HPos) && (HPosInput < ((*UserGraphicPtr).HPos + (*UserGraphicPtr).Width)) && (VPosInput >=
10335  (*UserGraphicPtr).VPos) && (VPosInput < ((*UserGraphicPtr).VPos + (*UserGraphicPtr).Height)))
10336  {
10337  UserGraphicItem = x;
10338  UserGraphicMoveHPos = (*UserGraphicPtr).HPos;
10339  UserGraphicMoveVPos = (*UserGraphicPtr).VPos;
10340  UserGraphicFoundFlag = true;
10341  Utilities->CallLogPop(2177);
10342  return;
10343  } // if ....
10344 
10345  } // for UserGraphicPtr...
10346  } // if !UserGraphicVector...
10347 
10348  Utilities->CallLogPop(2197);
10349 }
10350 
10351 // ---------------------------------------------------------------------------
10352 
10354 {
10355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RetrieveStripedNamedLocationGraphicsWhereRelevant," +
10356  TrackElement.LogTrack(11));
10357  Graphics::TBitmap *GraphicOutput = RailGraphics->bmTransparentBgnd; // default value
10358  int SpeedTag = TrackElement.SpeedTag;
10359 
10360  if(SpeedTag < 1)
10361  {
10362  throw Exception("Error - SpeedTag value " + AnsiString(SpeedTag) + " in RetrieveStripedNamedLocationGraphicsWhereRelevant");
10363  }
10364  switch(SpeedTag)
10365  {
10366  case 76: // t platform
10367  GraphicOutput = RailGraphics->gl76Striped;
10368  break;
10369 
10370  case 77: // h platform
10371  GraphicOutput = RailGraphics->bm77Striped;
10372  break;
10373 
10374  case 78: // v platform
10375  GraphicOutput = RailGraphics->bm78Striped;
10376  break;
10377 
10378  case 79: // r platform
10379  GraphicOutput = RailGraphics->gl79Striped;
10380  break;
10381 
10382  case 96: // concourse
10383  GraphicOutput = RailGraphics->ConcourseStriped;
10384  break;
10385 
10386  case 129: // v footbridge
10387  GraphicOutput = RailGraphics->gl129Striped;
10388  break;
10389 
10390  case 130: // h footbridge
10391  GraphicOutput = RailGraphics->gl130Striped;
10392  break;
10393 
10394  case 131: // non-station named loc
10395  GraphicOutput = RailGraphics->bmNameStriped;
10396  break;
10397 
10398  case 145: // v u'pass
10399  GraphicOutput = RailGraphics->gl145Striped;
10400  break;
10401 
10402  case 146: // h u'pass
10403  GraphicOutput = RailGraphics->gl146Striped;
10404  break;
10405 
10406  default:
10407  GraphicOutput = TrackElement.GraphicPtr;
10408  break;
10409  }
10410  Utilities->CallLogPop(642);
10411  return(GraphicOutput);
10412 }
10413 
10414 // ---------------------------------------------------------------------------
10415 
10417 {
10418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackElementAt," + AnsiString(At));
10419  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10420  {
10421 // Utilities->CallLogPop(2281); this shouldn't have been here
10422  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in TrackElementAt");
10423  }
10424  Utilities->CallLogPop(643);
10425  return(TrackVector.at(At));
10426 }
10427 
10428 // ---------------------------------------------------------------------------
10429 
10431 {
10432  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",InactiveTrackElementAt," + AnsiString(At));
10433  if((At < 0) || ((unsigned int)At >= InactiveTrackVector.size()))
10434  {
10435  throw Exception("Out of Range Error, vector size: " + AnsiString(InactiveTrackVector.size()) + ", At: " + AnsiString(At) +
10436  " in InactiveTrackElementAt");
10437  }
10438  Utilities->CallLogPop(644);
10439  return(InactiveTrackVector.at(At));
10440 }
10441 
10442 // ---------------------------------------------------------------------------
10443 
10444 bool TTrack::BlankElementAt(int Caller, int At) const
10445 {
10446  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BlankElementAt," + AnsiString(At));
10447  if((At < 0) || ((unsigned int)At >= TrackVector.size()))
10448  {
10449  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in BlankElementAt");
10450  }
10451  if(TrackVector.at(At).SpeedTag == 0) //have to use TrackVector.at because TrackElementAt is non-const
10452  {
10453  Utilities->CallLogPop(645);
10454  return(true);
10455  }
10456  else
10457  {
10458  Utilities->CallLogPop(646);
10459  return(false);
10460  }
10461 }
10462 
10463 // ---------------------------------------------------------------------------
10464 
10465 bool TTrack::OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
10466 /* Check sufficient elements with same ActiveTrackElementName linked together without any trailing point links to allow a train split.
10467  Only one length is needed to return true, but this doesn't mean that all platforms at the location are long enough. When a
10468  split is required a specific check is made using ThisNamedLocationLongEnoughForSplit.
10469  Need at least two linked ActiveTrackElementNames, with connected elements at each end, which may or may not be ActiveTrackElementNames,
10470  and no connections via point trailing links. Note that these conditions exclude opposed buffers since these not linked.
10471 */
10472 {
10473  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationLongEnoughForSplit," + LocationName);
10474  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10475  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10476  TLocationNameMultiMapIterator SNIterator;
10477  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10478 
10479  if(SNRange.first == SNRange.second)
10480  {
10481  Utilities->CallLogPop(972);
10482  return(false); // should have been caught earlier but include for completeness
10483  }
10484  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10485  {
10486  if(SNIterator->second < 0)
10487  {
10488  continue; // exclude footcrossings
10489  }
10490  InactiveElement = InactiveTrackElementAt(47, SNIterator->second);
10491  if(InactiveElement.TrackType == Concourse)
10492  {
10493  continue; // only interested in locations where ActiveTrackElementName may be set (not needed at v2.10.0 but leave in)
10494  }
10495  if(!TrackElementPresentAtHV(1, InactiveElement.HLoc, InactiveElement.VLoc)) //added at v2.10.0 in response to Jason Bassett error notified 14/08/21
10496  {
10497  continue; // only interested in locations where ActiveTrackElementName may be set
10498  }
10499  THVPair HVPair;
10500  HVPair.first = InactiveElement.HLoc;
10501  HVPair.second = InactiveElement.VLoc;
10502  if(TrackMap.find(HVPair) == TrackMap.end())
10503  {
10504  throw Exception
10505  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in OneNamedLocationLongEnoughForSplit (1)");
10506  }
10507  int TVPos = TrackMap.find(HVPair)->second;
10508  FirstNamedElement = TrackElementAt(560, TVPos);
10509  // first check linked on both sides, skip the check if not
10510  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10511  {
10512  continue;
10513  }
10514  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10515  // ActiveTrackElementNames are points and excluding trailing connections for points
10516  FirstNamedExitPos = 0;
10517  {
10518  SecondNamedElement = TrackElementAt(561, FirstNamedElement.Conn[FirstNamedExitPos]);
10519  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10520  FirstNamedLinkedElement = TrackElementAt(562, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10521  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10522  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10523  {
10524  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10525  {
10526  SecondNamedLinkedElement = TrackElementAt(563, SecondNamedElement.Conn[SecondNamedExitPos]);
10527  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10528  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10529  // success, now check FirstNamedElement link not trailing points & if so all OK
10530  {
10531  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10532  {
10533  Utilities->CallLogPop(1002);
10534  return(true);
10535  }
10536  }
10537  }
10538  }
10539  }
10540  // failed, try link 1
10541  FirstNamedExitPos = 1;
10542  {
10543  SecondNamedElement = TrackElementAt(564, FirstNamedElement.Conn[FirstNamedExitPos]);
10544  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10545  FirstNamedLinkedElement = TrackElementAt(565, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10546  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10547  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10548  {
10549  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10550  {
10551  SecondNamedLinkedElement = TrackElementAt(566, SecondNamedElement.Conn[SecondNamedExitPos]);
10552  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10553  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10554  // success, now check FirstNamedElement link not trailing points & if so all OK
10555  {
10556  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10557  {
10558  Utilities->CallLogPop(1003);
10559  return(true);
10560  }
10561  }
10562  }
10563  }
10564  }
10565  }
10566  Utilities->CallLogPop(1004);
10567  return(false);
10568 }
10569 
10570 // ---------------------------------------------------------------------------
10571 bool TTrack::ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos,
10572  int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
10573 // for success need two linked named location elements, so that one element of each train can be at the location
10574 // FirstNamedElementPos is the input vector position and the first (if successful) of the two linked named location elements,
10575 // the second is SecondNamedElementPos, and the two linked elements are FirstNamedLinkedElementPos and SecondNamedLinkedElementPos.
10576 // the two trains will occupy these 4 elements
10577 // All are track vector positions, all but the input being references and set within the function.
10578 {
10579 /* Check sufficient elements (including TrackvectorPosition) with same ActiveTrackElementName linked together without any trailing point
10580  links and including the element FirstNamedElementPos to allow a train split. Need at least two linked ActiveTrackElementNames, with
10581  connected elements at each end, which may or may not be ActiveTrackElementNames, and no connections via point trailing links. Note that
10582  these conditions exclude opposed buffers since these not linked. Return the two train positions and exit positions for use in train
10583  splitting.
10584 */
10585  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ThisNamedLocationLongEnoughForSplit," + LocationName +
10586  AnsiString(FirstNamedElementPos));
10587  TTrackElement InactiveElement, FirstNamedElement, SecondNamedElement, FirstNamedLinkedElement, SecondNamedLinkedElement;
10588  int FirstNamedExitPos, SecondNamedExitPos, FirstNamedLinkedExitPos, SecondNamedLinkedEntryPos;
10589 
10590  SecondNamedElementPos = -1;
10591  FirstNamedLinkedElementPos = -1;
10592  SecondNamedLinkedElementPos = -1;
10593  TLocationNameMultiMapIterator SNIterator;
10594  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10595 
10596  if(SNRange.first == SNRange.second) // i.e. location name not in map
10597  {
10598  Utilities->CallLogPop(1005);
10599  return(false); // should have been caught earlier but include for completeness
10600  }
10601  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10602  {
10603  if(SNIterator->second < 0)
10604  {
10605  continue; // exclude footcrossings
10606  }
10607  InactiveElement = InactiveTrackElementAt(69, SNIterator->second);
10608  if(InactiveElement.TrackType == Concourse)
10609  {
10610  continue; // only interested in locations where ActiveTrackElementName may be set
10611  }
10612  THVPair HVPair;
10613  HVPair.first = InactiveElement.HLoc;
10614  HVPair.second = InactiveElement.VLoc;
10615  if(TrackMap.find(HVPair) == TrackMap.end())
10616  {
10617  if(InactiveElement.TrackType == NamedNonStationLocation) // added at v2.2.0 to correct the error Xeon reported on 14/07/18.
10618  // If there is a NamedNonStationLocation without an associated active track element (effectively a non-station concourse)
10619  // then it won't be found in TrackMap but it's still legitimate.
10620  {
10621  continue;
10622  }
10623  else // for anything else throw the error
10624  {
10625  throw Exception
10626  ("Error - failed to find element in TrackMap for a non-concourse element in LocationNameMultiMap in ThisNamedLocationLongEnoughForSplit (2)"
10627  );
10628  }
10629  }
10630  int TVPos = TrackMap.find(HVPair)->second;
10631  if(TVPos != FirstNamedElementPos)
10632  {
10633  continue; // looking for an exact match
10634  }
10635  FirstNamedElement = TrackElementAt(567, TVPos);
10636  // first check linked on both sides, skip the check if not
10637  if((FirstNamedElement.Conn[0] == -1) || (FirstNamedElement.Conn[1] == -1))
10638  {
10639  continue;
10640  }
10641  // check if another ActiveTrackElementName connected via link pos 0 (can only be 0 or 1 since the only 2-track elements that can be
10642  // ActiveTrackElementNames are points and excluding trailing connections for points
10643  FirstNamedExitPos = 0;
10644  {
10645  SecondNamedElement = TrackElementAt(568, FirstNamedElement.Conn[FirstNamedExitPos]);
10646  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10647  FirstNamedLinkedElement = TrackElementAt(569, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10648  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10649  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10650  {
10651  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10652  {
10653  SecondNamedLinkedElement = TrackElementAt(570, SecondNamedElement.Conn[SecondNamedExitPos]);
10654  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10655  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10656  // success, now check FirstNamedElement link not trailing points & if so all OK
10657  {
10658  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10659  {
10660  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10661  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10662  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10663  Utilities->CallLogPop(1006);
10664  return(true);
10665  }
10666  }
10667  }
10668  }
10669  }
10670  // failed, try link 1
10671  FirstNamedExitPos = 1;
10672  {
10673  SecondNamedElement = TrackElementAt(571, FirstNamedElement.Conn[FirstNamedExitPos]);
10674  SecondNamedExitPos = GetNonPointsOppositeLinkPos(FirstNamedElement.ConnLinkPos[FirstNamedExitPos]);
10675  FirstNamedLinkedElement = TrackElementAt(572, FirstNamedElement.Conn[1 - FirstNamedExitPos]);
10676  FirstNamedLinkedExitPos = FirstNamedElement.ConnLinkPos[1 - FirstNamedExitPos];
10677  if(SecondNamedElement.ActiveTrackElementName == LocationName) // success - check if it's connected on the far side
10678  {
10679  if(SecondNamedElement.Conn[SecondNamedExitPos] > -1)
10680  {
10681  SecondNamedLinkedElement = TrackElementAt(573, SecondNamedElement.Conn[SecondNamedExitPos]);
10682  SecondNamedLinkedEntryPos = SecondNamedElement.ConnLinkPos[SecondNamedExitPos];
10683  if((SecondNamedLinkedElement.TrackType != Points) || (SecondNamedLinkedEntryPos != 3))
10684  // success, now check FirstNamedElement link not trailing points & if so all OK
10685  {
10686  if((FirstNamedLinkedElement.TrackType != Points) || (FirstNamedLinkedExitPos != 3))
10687  {
10688  SecondNamedElementPos = FirstNamedElement.Conn[FirstNamedExitPos];
10689  FirstNamedLinkedElementPos = FirstNamedElement.Conn[1 - FirstNamedExitPos];
10690  SecondNamedLinkedElementPos = SecondNamedElement.Conn[SecondNamedExitPos];
10691  Utilities->CallLogPop(1007);
10692  return(true);
10693  }
10694  }
10695  }
10696  }
10697  }
10698  }
10699  Utilities->CallLogPop(1008);
10700  return(false);
10701 }
10702 
10703 // ---------------------------------------------------------------------------
10704 
10705 bool TTrack::OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
10706 {
10707  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OneNamedLocationElementAtLocation," + LocationName);
10708  TLocationNameMultiMapIterator SNIterator;
10709  TLocationNameMultiMapRange SNRange = LocationNameMultiMap.equal_range(LocationName);
10710 
10711  if(SNRange.first != SNRange.second)
10712  {
10713  for(SNIterator = SNRange.first; SNIterator != SNRange.second; SNIterator++)
10714  {
10715  if(SNIterator->second < 0)
10716  {
10717  continue; // only looking for inactive (platform or NamedNonStationLocation) elements
10718  }
10719  if((InactiveTrackElementAt(33, SNIterator->second).TrackType == Platform) || (InactiveTrackElementAt(81,
10720  SNIterator->second).TrackType == NamedNonStationLocation))
10721  {
10722  Utilities->CallLogPop(1121);
10723  return(true);
10724  }
10725  }
10726  }
10727  Utilities->CallLogPop(848);
10728  return(false);
10729 }
10730 
10731 // ---------------------------------------------------------------------------
10732 
10733 bool TTrack::PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap* &SignalPlatformGraphic)
10734 {
10735 // dropped special platforms at v0.6 as didn't show well against ground signals & not needed anyway as plats always plotted first where there are signals
10736  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PlatformOnSignalSide," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
10737  "," + AnsiString(SpeedTag));
10738  if(!IsPlatformOrNamedNonStationLocationPresent(5, HLoc, VLoc)) // can't be a named location so no ambiguity
10739  {
10740  Utilities->CallLogPop(949);
10741  return(false);
10742  }
10743  bool FoundFlag;
10744  TIMPair IMPair = GetVectorPositionsFromInactiveTrackMap(27, HLoc, VLoc, FoundFlag);
10745 
10746  if(!FoundFlag)
10747  {
10748  throw Exception("Error, FoundFlag false in PlatformOnSignalSide after IsPlatformOrNamedNonStationLocationPresent called successfully");
10749  }
10750  TTrackElement IAElement;
10751 
10752  if(SpeedTag == 68) // top sig
10753  {
10754  if((InactiveTrackElementAt(22, IMPair.first).SpeedTag == 76) || (InactiveTrackElementAt(23, IMPair.second).SpeedTag == 76)) // top plat
10755  {
10756  if(InactiveTrackElementAt(49, IMPair.first).SpeedTag == 76)
10757  {
10758  IAElement = InactiveTrackElementAt(50, IMPair.first);
10759  }
10760  else
10761  {
10762  IAElement = InactiveTrackElementAt(51, IMPair.second);
10763  }
10764  if(IAElement.LocationName == "")
10765  {
10766 // SignalPlatformGraphic = RailGraphics->Plat68Striped;
10767  SignalPlatformGraphic = RailGraphics->gl76Striped;
10768  }
10769  else
10770  {
10771 // SignalPlatformGraphic = RailGraphics->Plat68;
10772  SignalPlatformGraphic = RailGraphics->gl76;
10773  }
10774  Utilities->CallLogPop(950);
10775  return(true);
10776  }
10777  }
10778  else if(SpeedTag == 69) // bot sig
10779  {
10780  if((InactiveTrackElementAt(70, IMPair.first).SpeedTag == 77) || (InactiveTrackElementAt(75, IMPair.second).SpeedTag == 77)) // bot plat
10781  {
10782  if(InactiveTrackElementAt(76, IMPair.first).SpeedTag == 77)
10783  {
10784  IAElement = InactiveTrackElementAt(77, IMPair.first);
10785  }
10786  else
10787  {
10788  IAElement = InactiveTrackElementAt(78, IMPair.second);
10789  }
10790  if(IAElement.LocationName == "")
10791  {
10792 // SignalPlatformGraphic = RailGraphics->Plat69Striped;
10793  SignalPlatformGraphic = RailGraphics->bm77Striped;
10794  }
10795  else
10796  {
10797 // SignalPlatformGraphic = RailGraphics->Plat69;
10798  SignalPlatformGraphic = RailGraphics->bm77;
10799  }
10800  Utilities->CallLogPop(951);
10801  return(true);
10802  }
10803  }
10804  else if(SpeedTag == 70) // left sig
10805  {
10806  if((InactiveTrackElementAt(52, IMPair.first).SpeedTag == 78) || (InactiveTrackElementAt(79, IMPair.second).SpeedTag == 78)) // left plat
10807  {
10808  if(InactiveTrackElementAt(80, IMPair.first).SpeedTag == 78)
10809  {
10810  IAElement = InactiveTrackElementAt(55, IMPair.first);
10811  }
10812  else
10813  {
10814  IAElement = InactiveTrackElementAt(82, IMPair.second);
10815  }
10816  if(IAElement.LocationName == "")
10817  {
10818 // SignalPlatformGraphic = RailGraphics->Plat70Striped;
10819  SignalPlatformGraphic = RailGraphics->bm78Striped;
10820  }
10821  else
10822  {
10823 // SignalPlatformGraphic = RailGraphics->Plat70;
10824  SignalPlatformGraphic = RailGraphics->bm78;
10825  }
10826  Utilities->CallLogPop(952);
10827  return(true);
10828  }
10829  }
10830  else if(SpeedTag == 71) // right sig
10831  {
10832  if((InactiveTrackElementAt(83, IMPair.first).SpeedTag == 79) || (InactiveTrackElementAt(58, IMPair.second).SpeedTag == 79)) // right plat
10833  {
10834  if(InactiveTrackElementAt(84, IMPair.first).SpeedTag == 79)
10835  {
10836  IAElement = InactiveTrackElementAt(85, IMPair.first);
10837  }
10838  else
10839  {
10840  IAElement = InactiveTrackElementAt(86, IMPair.second);
10841  }
10842  if(IAElement.LocationName == "")
10843  {
10844 // SignalPlatformGraphic = RailGraphics->Plat71Striped;
10845  SignalPlatformGraphic = RailGraphics->gl79Striped;
10846  }
10847  else
10848  {
10849 // SignalPlatformGraphic = RailGraphics->Plat71;
10850  SignalPlatformGraphic = RailGraphics->gl79;
10851  }
10852  Utilities->CallLogPop(953);
10853  return(true);
10854  }
10855  }
10856  Utilities->CallLogPop(954);
10857  return(false);
10858 }
10859 
10860 // ---------------------------------------------------------------------------
10861 
10862 bool TTrack::OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
10863 // returns true if another train on NextEntryPos track of element at NextPos, whether bridge or not
10864 // false if not, if NextPos == -1, or if only own train on the track
10865 {
10866  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",OtherTrainOnTrack," + AnsiString(NextPos) + "," +
10867  AnsiString(NextEntryPos) + "," + AnsiString(OwnTrainID));
10868  if(NextEntryPos < 0)
10869  {
10870  Utilities->CallLogPop(1348);
10871  return(false);
10872  }
10873  TTrackElement TrackElement = TrackElementAt(713, NextPos);
10874 
10875  if(TrackElement.TrackType != Bridge)
10876  {
10877  Utilities->CallLogPop(1349);
10878  return ((TrackElement.TrainIDOnElement > -1) && (TrackElement.TrainIDOnElement != OwnTrainID));
10879  }
10880 // bridge if reach here
10881  if(NextEntryPos > 1)
10882  {
10883  Utilities->CallLogPop(1350);
10884  return ((TrackElement.TrainIDOnBridgeTrackPos23 > -1) && (TrackElement.TrainIDOnBridgeTrackPos23 != OwnTrainID));
10885  }
10886  else
10887  {
10888  Utilities->CallLogPop(1351);
10889  return ((TrackElement.TrainIDOnBridgeTrackPos01 > -1) && (TrackElement.TrainIDOnBridgeTrackPos01 != OwnTrainID));
10890  }
10891 }
10892 
10893 // ---------------------------------------------------------------------------
10894 
10896 {
10897  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SelectVectorAt," + AnsiString(At));
10898  if((At < 0) || ((unsigned int)At >= SelectVectorSize()))
10899  {
10900  throw Exception("Out of Range Error, vector size: " + AnsiString(TrackVector.size()) + ", At: " + AnsiString(At) + " in SelectVectorAt");
10901  }
10902  Utilities->CallLogPop(1483);
10903  return(SelectVector.at(At));
10904 }
10905 
10906 // ---------------------------------------------------------------------------
10907 
10908 bool TTrack::IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
10909 // For element at HLoc & VLoc, returns true if there is an element adjacent to LinkIn
10910 {
10911  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsATrackElementAdjacentToLink," + AnsiString(HLocIn) + "," +
10912  AnsiString(VLocIn) + "," + AnsiString(LinkIn));
10913  bool FoundFlag = false;
10914  int NewHLoc = HLocIn + LinkHVArray[LinkIn][0];
10915  int NewVLoc = VLocIn + LinkHVArray[LinkIn][1];
10916 
10917  GetVectorPositionFromTrackMap(41, NewHLoc, NewVLoc, FoundFlag);
10918  Utilities->CallLogPop(1538);
10919  return(FoundFlag);
10920 }
10921 
10922 // ---------------------------------------------------------------------------
10923 
10924 bool TTrack::FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
10925 {
10926 // return true if find an inactive element called 'Name'
10927  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindHighestAndLowestNamedElements," + Name);
10928  int VLocHi = -2000000000, VLocLo = 2000000000, HLoc = 2000000000;
10929  bool FoundFlag = false;
10930 
10931  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
10932  {
10933  if(InactiveTrackElementAt(158, x).LocationName == Name)
10934  {
10935  FoundFlag = true;
10936  int V = InactiveTrackElementAt(159, x).VLoc;
10937  int H = InactiveTrackElementAt(160, x).HLoc;
10938  if(V > VLocHi)
10939  {
10940  VLocHi = V;
10941  }
10942  if(V < VLocLo)
10943  {
10944  VLocLo = V;
10945  }
10946  if(H < HLoc)
10947  {
10948  HLoc = H;
10949  }
10950  }
10951  }
10952  if(FoundFlag)
10953  {
10954  VPosHi = 16 * VLocHi;
10955  VPosLo = 16 * VLocLo;
10956  HPos = 16 * HLoc;
10957  Utilities->CallLogPop(1562);
10958  return(true);
10959  }
10960  else
10961  {
10962  Utilities->CallLogPop(1563);
10963  return(false);
10964  }
10965 }
10966 
10967 // ---------------------------------------------------------------------------
10968 
10969 int TTrack::FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
10970 {
10971 // return the link array position for the element at StartTVPosition that gives the closest link to the element at EndTVPosition
10972 // NB the StartTVPosition is expected to be a single track element as only positions 0 & 1 are checked
10973  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindClosestLinkPosition," + AnsiString(StartTVPosition) + "," +
10974  AnsiString(EndTVPosition));
10975  TTrackElement &StartElement = TrackElementAt(839, StartTVPosition);
10976  TTrackElement &EndElement = TrackElementAt(840, EndTVPosition);
10977 
10978 // get H & V values for the element adjacent to Link[0] & Link[1]
10979  int NewHLocLink0 = StartElement.HLoc + LinkHVArray[StartElement.Link[0]][0];
10980  int NewVLocLink0 = StartElement.VLoc + LinkHVArray[StartElement.Link[0]][1];
10981  int NewHLocLink1 = StartElement.HLoc + LinkHVArray[StartElement.Link[1]][0];
10982  int NewVLocLink1 = StartElement.VLoc + LinkHVArray[StartElement.Link[1]][1];
10983 
10984 // compute the sum of the squares of the H & V distances between EndElement and 'New' values
10985  int Link0Squares = ((EndElement.HLoc - NewHLocLink0) * (EndElement.HLoc - NewHLocLink0)) +
10986  ((EndElement.VLoc - NewVLocLink0) * (EndElement.VLoc - NewVLocLink0));
10987  int Link1Squares = ((EndElement.HLoc - NewHLocLink1) * (EndElement.HLoc - NewHLocLink1)) +
10988  ((EndElement.VLoc - NewVLocLink1) * (EndElement.VLoc - NewVLocLink1));
10989 
10990  if(Link0Squares <= Link1Squares)
10991  {
10992  Utilities->CallLogPop(1851);
10993  return(0);
10994  }
10995  else
10996  {
10997  Utilities->CallLogPop(1852);
10998  return(1);
10999  }
11000 }
11001 
11002 // ---------------------------------------------------------------------------
11003 
11004 int TTrack::GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
11005 {
11006  // element can be points or any other type
11007  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAnyElementOppositeLinkPos," + AnsiString(TrackVectorPosition) + "," +
11008  AnsiString(LinkPos));
11009  Derail = false;
11010  TTrackElement &TE = Track->TrackElementAt(277, TrackVectorPosition);
11011 
11012  if((TE.TrackType == Points) && (TE.Config[LinkPos] == Lead))
11013  {
11014  if(TE.Attribute == 0)
11015  {
11016  Utilities->CallLogPop(663);
11017  return(1); // Att == 0 & ExitPos == 1 represent straight
11018  }
11019  else
11020  {
11021  Utilities->CallLogPop(664);
11022  return(3); // Att == 1 & ExitPos == 3 represent diverging
11023  }
11024  }
11025  else if((TE.TrackType == Points) && (TE.Config[LinkPos] == Trail))
11026  {
11027  if((LinkPos == 1) && (TE.Attribute == 0))
11028  {
11029  Utilities->CallLogPop(665);
11030  return(0); // Att == 0 represents straight
11031  }
11032  else if(LinkPos == 1)
11033  {
11034  Derail = true;
11035  Utilities->CallLogPop(666);
11036  return(0);
11037  }
11038  else if((LinkPos == 3) && (TE.Attribute == 1))
11039  {
11040  Utilities->CallLogPop(667);
11041  return(0);
11042  }
11043  else if(LinkPos == 3)
11044  {
11045  Derail = true;
11046  Utilities->CallLogPop(668);
11047  return(0);
11048  }
11049  }
11050  else if(LinkPos == 0)
11051  {
11052  Utilities->CallLogPop(669);
11053  return(1);
11054  }
11055  else if(LinkPos == 1)
11056  {
11057  Utilities->CallLogPop(670);
11058  return(0);
11059  }
11060  else if(LinkPos == 2)
11061  {
11062  Utilities->CallLogPop(671);
11063  return(3);
11064  }
11065  else if(LinkPos == 3)
11066  {
11067  Utilities->CallLogPop(672);
11068  return(2);
11069  }
11070  throw Exception("Error, failure in GetExitPos"); // should never reach here
11071 }
11072 
11073 // ----------------------------------------------------------------------------
11074 
11076 {
11077  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PopulateLCVector");
11078  LCVector.clear();
11079  for(unsigned int x = 0; x < InactiveTrackVector.size(); x++)
11080  {
11081  if(InactiveTrackElementAt(161, x).TrackType == LevelCrossing)
11082  {
11083  LCVector.push_back(x);
11084  }
11085  }
11086  Utilities->CallLogPop(1931);
11087  return;
11088 }
11089 
11090 // ---------------------------------------------------------------------------
11091 
11092 bool TTrack::TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID) // new at v1.2.0
11093 /*
11094  Call GetVectorPositionFromTrackMap to identify the track element, then check if TrainIDOnElement > -1 (if a
11095  bridge then check relevant TrainID according to the Link), and if absent return false. If present identify
11096  the train using TrainController->TrainVectorAtIdent, and check which bit on the element in question (Lead, Mid or Lag),
11097  and then check the relevant EntryPos & ExitPos for a match with Link. If find a match return true and return the TrainID.
11098 */
11099 {
11100  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrainOnLink," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
11101  AnsiString(Link));
11102  bool FoundFlag;
11103 
11104  TrainID = -1;
11105  int VecPos = GetVectorPositionFromTrackMap(47, HLoc, VLoc, FoundFlag);
11106 
11107  if(!FoundFlag)
11108  {
11109  Utilities->CallLogPop(2001);
11110  return(false);
11111  }
11112  TTrackElement TE = TrackElementAt(882, VecPos);
11113 
11114  TrainID = TE.TrainIDOnElement;
11115  if(TE.TrackType == Bridge)
11116  {
11117  if(TE.TrainIDOnElement > -1)
11118  {
11119  if((TE.Link[0] == Link) || (TE.Link[1] == Link))
11120  {
11121  TrainID = TE.TrainIDOnBridgeTrackPos01;
11122  }
11123  else if((TE.Link[2] == Link) || (TE.Link[3] == Link))
11124  {
11125  TrainID = TE.TrainIDOnBridgeTrackPos23;
11126  }
11127  else
11128  {
11129  TrainID = -1; // shouldn't ever reach here but be safe
11130  }
11131  }
11132  }
11133  if(TrainID == -1)
11134  {
11135  Utilities->CallLogPop(2002);
11136  return(false);
11137  }
11138 // now get the train
11139  TTrain Train = TrainController->TrainVectorAtIdent(38, TrainID);
11140 
11141  if(Train.LinkOccupied(0, VecPos, Link)) // checks whether any part of train occupying Link on VecPos
11142  {
11143  Utilities->CallLogPop(2003);
11144  return(true);
11145  }
11146  TrainID = -1;
11147  Utilities->CallLogPop(2004);
11148  return(false);
11149 }
11150 
11151 // ---------------------------------------------------------------------------
11152 
11153 bool TTrack::DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
11154 /* New at v1.2.0
11155  As DiagonalFouledByRouteOrTarin but checks for a train only (may or may not be a route) and returns the ID number. Enter with H & V set for the element whose diagonal
11156  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
11157  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
11158  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
11159  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
11160  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
11161  Each of these is examined in turn for each route element in the relevant position.
11162 */
11163 {
11164  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByTrain," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
11165  "," + AnsiString(DiagonalLinkNumber));
11166  TrainID = -1;
11167  TPrefDirElement TempPrefDirElement;
11168  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
11169 
11170  if(((DiagonalLinkNumber == 1) && TrainOnLink(8, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && TrainOnLink(9, HLoc - 1, VLoc, 9, TrainID)))
11171  {
11172  Utilities->CallLogPop(2027);
11173  return(true);
11174  }
11175  if(((DiagonalLinkNumber == 1) && TrainOnLink(10, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && TrainOnLink(11, HLoc, VLoc - 1, 9, TrainID)))
11176  {
11177  Utilities->CallLogPop(2028);
11178  return(true);
11179  }
11180  if(((DiagonalLinkNumber == 3) && TrainOnLink(12, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(13, HLoc + 1, VLoc, 7, TrainID)))
11181  {
11182  Utilities->CallLogPop(2029);
11183  return(true);
11184  }
11185  if(((DiagonalLinkNumber == 7) && TrainOnLink(14, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && TrainOnLink(15, HLoc, VLoc + 1, 3, TrainID)))
11186  {
11187  Utilities->CallLogPop(2030);
11188  return(true);
11189  }
11190  Utilities->CallLogPop(2031);
11191  return(false);
11192 }
11193 
11194 // ---------------------------------------------------------------------------
11195 
11196 void TTrack::SaveUserGraphics(int Caller, std::ofstream &VecFile)
11197 {
11198  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveUserGraphics");
11199  Utilities->SaveFileInt(VecFile, UserGraphicVector.size()); // number of items
11200  TUserGraphicItem UGI;
11201  AnsiString JustFileName = "";
11202 
11203  for(unsigned int x = 0; x < UserGraphicVector.size(); x++)
11204  {
11205  UGI = UserGraphicVectorAt(17, x);
11206  int LastDelim = UGI.FileName.LastDelimiter('\\');
11207  if(LastDelim == 0) // can't find it so skip this item
11208  {
11209  continue;
11210  }
11211  else
11212  {
11213  JustFileName = UGI.FileName.SubString(LastDelim + 1, UGI.FileName.Length() - LastDelim);
11214  }
11215  Utilities->SaveFileString(VecFile, JustFileName);
11216  Utilities->SaveFileInt(VecFile, UGI.HPos);
11217  Utilities->SaveFileInt(VecFile, UGI.VPos);
11218  }
11219  Utilities->CallLogPop(2178);
11220 }
11221 
11222 // ---------------------------------------------------------------------------
11223 
11224 int TTrack::NumberOfPlatforms(int Caller, AnsiString LocationName)
11225 //checks all active track elements and lists those with ActiveTrackElementName same as LocationName in NamePosVector
11226 {
11227  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",NumberOfPlatforms," + LocationName);
11228  int NumPlats = 0;
11229  TTrackElement TempElement;
11230  int TempInt;
11231 
11232  typedef std::list<int> TNamePosList;
11233  TNamePosList NamePosList;
11234  typedef TNamePosList::iterator TNPLIt;
11235  TNPLIt NPLIt;
11236  typedef std::list<int> TOnePlatList;
11237  TOnePlatList OnePlatList;
11238  typedef TOnePlatList::iterator TOPLIt;
11239  TOPLIt OPLIt;
11240 
11241  NamePosList.clear();
11242  OnePlatList.clear();
11243  for(unsigned int x = 0; x < TrackVector.size(); x++)
11244  {
11245  if(TrackElementAt(988, x).ActiveTrackElementName == LocationName)
11246  {
11247  NamePosList.push_back(x);
11248  }
11249  }
11250  //NamePosList complete
11251 
11252  if(!NamePosList.empty()) //first value for the loop examination
11253  {
11254  OnePlatList.push_back(NamePosList.back());
11255  NamePosList.pop_back(); //erase from NPV as done with it here
11256  }
11257  while(!OnePlatList.empty()) //loop to examine all linked elements
11258  {
11259  TempInt = OnePlatList.front();
11260  TempElement = TrackElementAt(989, TempInt);
11261 
11262  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[0]);
11263  if(NPLIt != NamePosList.end() && ((TempElement.Link[0] == 2) || (TempElement.Link[0] == 4) || (TempElement.Link[0] == 6) || (TempElement.Link[0] == 8)))
11264  {
11265  OnePlatList.push_back(TempElement.Conn[0]);
11266  NamePosList.erase(NPLIt);
11267  }
11268  NPLIt = find(NamePosList.begin(), NamePosList.end(), TempElement.Conn[1]);
11269  if(NPLIt != NamePosList.end() && ((TempElement.Link[1] == 2) || (TempElement.Link[1] == 4) || (TempElement.Link[1] == 6) || (TempElement.Link[1] == 8)))
11270  {
11271  OnePlatList.push_back(TempElement.Conn[1]);
11272  NamePosList.erase(NPLIt);
11273  }
11274  //here when loaded any connecting links into OnePlatList, so can erase the front element
11275  OnePlatList.erase(OnePlatList.begin());
11276  if(OnePlatList.empty())
11277  {
11278  NumPlats++; //finished with current linked elements so can increment NumPlats
11279  if(!NamePosList.empty())
11280  {
11281  OnePlatList.push_back(NamePosList.back()); //ready for next iteration
11282  NamePosList.pop_back(); //erase from NPV as done with it there
11283  }
11284  }
11285  }
11286  Utilities->CallLogPop(2218);
11287  return(NumPlats);
11288 }
11289 
11290 // ---------------------------------------------------------------------------
11291 // UserGraphic, PrefDir & Route functions
11292 // ---------------------------------------------------------------------------
11293 
11295 {
11296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",UserGraphicVectorAt," + AnsiString(At));
11297  if((At < 0) || ((unsigned int)At >= UserGraphicVector.size()))
11298  {
11299  throw Exception("Out of Range Error, vector size: " + AnsiString(UserGraphicVector.size()) + ", At: " + AnsiString(At) + " in UserGraphicVectorAt");
11300  }
11301  Utilities->CallLogPop(2194);
11302  return(UserGraphicVector.at(At));
11303 }
11304 
11305 // ---------------------------------------------------------------------------
11306 
11307 int TOnePrefDir::LastElementNumber(int Caller) const
11308 {
11309  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementNumber,");
11310  int RetVal = PrefDirVector.size() - 1;
11311 
11312  if(RetVal < 0)
11313  {
11314  throw Exception("Return value negative in call to LastElementNumber");
11315  }
11316  Utilities->CallLogPop(114);
11317  return(RetVal);
11318 }
11319 
11320 // ---------------------------------------------------------------------------
11322 {
11323  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LastElementPtr,");
11324  if(PrefDirVector.empty())
11325  {
11326  throw Exception("PrefDirVector empty in call to LastElementPtr");
11327  }
11328  TPrefDirVectorIterator RetIT = PrefDirVector.end() - 1;
11329 
11330  Utilities->CallLogPop(115);
11331  return(RetIT);
11332 }
11333 
11334 // ---------------------------------------------------------------------------
11336 {
11337  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedPrefDirElementAt," + AnsiString(At));
11338  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11339  {
11340  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) + " in GetFixedPrefDirElementAt");
11341  }
11342  Utilities->CallLogPop(116);
11343  return(PrefDirVector.at(At));
11344 }
11345 
11346 // ---------------------------------------------------------------------------
11348 {
11349  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiablePrefDirElementAt," + AnsiString(At));
11350  if((At < 0) || ((unsigned int)At >= PrefDirVector.size()))
11351  {
11352  throw Exception("Out of Range Error, vector size: " + AnsiString(PrefDirVector.size()) + ", At: " + AnsiString(At) +
11353  " in GetModifiablePrefDirElementAt");
11354  }
11355  Utilities->CallLogPop(117);
11356  return(PrefDirVector.at(At));
11357 }
11358 
11359 // ---------------------------------------------------------------------------
11361 {
11362  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedSearchElementAt," + AnsiString(At));
11363  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11364  {
11365  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetFixedSearchElementAt");
11366  }
11367  Utilities->CallLogPop(118);
11368  return(SearchVector.at(At));
11369 }
11370 
11371 // ---------------------------------------------------------------------------
11373 {
11374  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableSearchElementAt," + AnsiString(At));
11375  if((At < 0) || ((unsigned int)At >= SearchVector.size()))
11376  {
11377  throw Exception("Out of Range Error, vector size: " + AnsiString(SearchVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableSearchElementAt");
11378  }
11379  Utilities->CallLogPop(119);
11380  return(SearchVector.at(At));
11381 }
11382 
11383 // ---------------------------------------------------------------------------
11384 bool TOnePrefDir::GetPrefDirStartElement(int Caller, int HLoc, int VLoc) // Return true if OK.
11385 /*
11386  Enter with HLoc & VLoc set to selected element. Clear PrefDirVector, check if selected element
11387  is a valid track element & return false if not. Create a TPrefDirElement from the track element and
11388  set checkcount to 4 to cover the fixed values, then add to PrefDirVector. All variable values are
11389  set in later functions.
11390 */
11391 {
11392  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirStartElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11393  ClearPrefDir();
11394  int TrackVectorPosition;
11395  TTrackElement TrackElement;
11396 
11397  if(!(Track->FindNonPlatformMatch(5, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11398  {
11399  Utilities->CallLogPop(126);
11400  return(false);
11401  }
11402 /* it can be points so drop the code below - all exits are checked, no assumptions are made about the exit position of the start element
11403  if(TrackElement.TrackType == Points)
11404  {
11405  ShowMessage("Can't start on points");//because if PrefDir leads away from the leading edge
11406  //it isn't known which trailing edge is the required PrefDir - could use the straight as
11407  //default but may already be a PrefDir up to the diverging edge, then will have a mismatch,
11408  //best to prevent it to avoid problems
11409  Utilities->CallLogPop(127);
11410  return false;
11411  }
11412 */
11413  TPrefDirElement PrefDirElement(TrackElement);
11414 
11415  PrefDirElement.TrackVectorPosition = TrackVectorPosition;
11416  PrefDirElement.CheckCount = 4; // HLoc, VLoc, SpeedTag & TrackVectorPosition
11417  StorePrefDirElement(1, PrefDirElement); // enter first element
11418 // Note that ELink not set even if a buffer or continuation - these set in
11419 // ConvertPrefDirSearchVector after 2nd element added
11420 
11421  Utilities->CallLogPop(128);
11422  return(true);
11423 }
11424 
11425 // ---------------------------------------------------------------------------
11426 bool TOnePrefDir::GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
11427 
11428 /*
11429  Enter with HLoc & VLoc set to selected element. If not a track element or if PrefDirVector empty return false.
11430  Examine the last element in the PrefDirvector, if ELink not set (start element) do an immediate
11431  check for an adjacent find (i.e. find selected element), & if succeed use SearchForPrefDir with that as XLinkPos to deal
11432  with setting the PrefDir vector, & return true. Also set FinishElement if found element was a buffer or continuation,
11433  so that the calling function knows that the PrefDir is complete.
11434  If last element was the start element but no immediate find, search on each valid exit pos in turn, using
11435  SearchForPrefDir to examine all branches. If succeed set PrefDirvector & finishelement as appropriate.
11436  Otherwise (last element not start element) check if last element was a leading point (if so can't be first element)
11437  & check again for an immediate find on either XLinkPos values 1 & 3, using SearchForPrefDir &
11438  ConvertPrefDirSearchVector to set PrefDirVector. Set FinishElement appropriately.
11439  If a leading point but not an immediate find use SearchForPrefDir on the XLinkPos values 1 & 3 in turn.
11440  If it wasn't a leading point just use XLinkPos value corresponding to XLink & Search on that. If don't
11441  find the required element return false. CheckCount is used to keep track of set values to allow check later.
11442 */
11443 
11444 {
11445  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPrefDirElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
11446  FinishElement = false;
11447  int TrackVectorPosition;
11448 
11449  TotalSearchCount = 0;
11450  TTrackElement TrackElement, TempTrackElement;
11451 
11452  if(PrefDirVector.size() == 0)
11453  {
11454  Utilities->CallLogPop(129);
11455  return(false);
11456  }
11457  if(!(Track->FindNonPlatformMatch(6, HLoc, VLoc, TrackVectorPosition, TrackElement)))
11458  {
11459  Utilities->CallLogPop(130);
11460  return(false);
11461  }
11462 // set the search limits using the last stored element in PrefDirVector as the start point
11463 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
11464 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
11465 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
11466 
11467  TPrefDirElement StartPrefDirElement = PrefDirVector.at(LastElementNumber(72));
11468 
11469  if(TrackElement.HLoc >= StartPrefDirElement.HLoc)
11470  {
11471  SearchLimitLowH = StartPrefDirElement.HLoc - 15;
11472  SearchLimitHighH = TrackElement.HLoc + 15;
11473  }
11474  else
11475  {
11476  SearchLimitLowH = TrackElement.HLoc - 15;
11477  SearchLimitHighH = StartPrefDirElement.HLoc + 15;
11478  }
11479  if(TrackElement.VLoc >= StartPrefDirElement.VLoc)
11480  {
11481  SearchLimitLowV = StartPrefDirElement.VLoc - 15;
11482  SearchLimitHighV = TrackElement.VLoc + 15;
11483  }
11484  else
11485  {
11486  SearchLimitLowV = TrackElement.VLoc - 15;
11487  SearchLimitHighV = StartPrefDirElement.VLoc + 15;
11488  }
11489 /* dropped this for v0.4d - prevents ability to set paths for gaps that are widely separated, ok without it as search limited by SearchVector size
11490  check & TotalSearchCounts check
11491  if((abs(TrackElement.HLoc - StartPrefDirElement.HLoc) > 120) || (abs(TrackElement.VLoc - StartPrefDirElement.VLoc) > 120))
11492  {
11493  ShowMessage("Unable to reach the selected element - too far ahead");
11494  Utilities->CallLogPop(1692);
11495  return false;
11496  }
11497 */
11498 // get last PrefDir element
11499  if(PrefDirVector.at(LastElementNumber(0)).ELink == -1) // start element
11500  {
11501  // check if TrackElement adjacent to any of the 4 XLinkPos'
11502  for(int x = 0; x < 4; x++)
11503  {
11504  if(PrefDirVector.at(LastElementNumber(1)).Conn[x] == TrackVectorPosition)
11505  {
11506  PrefDirVector.at(LastElementNumber(2)).XLinkPos = x;
11507  PrefDirVector.at(LastElementNumber(3)).XLink = PrefDirVector.at(LastElementNumber(4)).Link[x];
11508  PrefDirVector.at(LastElementNumber(5)).CheckCount++;
11509  PrefDirVector.at(LastElementNumber(6)).CheckCount++;
11510  break; // can have 2 connections if have 2 adjacent gaps connected to each other but ELink & XLink
11511  // then ambiguous. Have to opt for just one, and if user wanted the other then that's unfortunate,
11512  // shouldn't ever get it in a serious railway though.
11513 // Note: ELink & ELinkPos are set in ConvertPrefDirSearchVector for the start element
11514  }
11515  }
11516  if(PrefDirVector.at(LastElementNumber(7)).XLinkPos > -1) // i.e required position must be adjacent to the start element
11517  {
11518  TempTrackElement = PrefDirVector.at(LastElementNumber(8));
11519  SearchVector.clear(); // use this & convert to set all PrefDir element values
11520  if(SearchForPrefDir(1, TempTrackElement, PrefDirVector.at(LastElementNumber(9)).XLinkPos, TrackVectorPosition))
11521  {
11523  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11524  {
11525  FinishElement = true;
11526  }
11527  Utilities->CallLogPop(131);
11528  return(true);
11529  }
11530  } // not an adjacent element
11531 
11532  // now check each of the 4 possible XLinkPos values
11533  for(int x = 0; x < 4; x++)
11534  {
11535  if((PrefDirVector.at(LastElementNumber(10)).Link[x] > 0) && (PrefDirVector.at(LastElementNumber(11)).Config[x] != End)) // i.e have somewhere to go
11536  {
11537  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find the required position
11538  TempTrackElement = PrefDirVector.at(LastElementNumber(12));
11539  SearchVector.clear();
11540  if(SearchForPrefDir(2, TempTrackElement, x, TrackVectorPosition))
11541  {
11543  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11544  {
11545  FinishElement = true;
11546  }
11547  Utilities->CallLogPop(132);
11548  return(true);
11549  }
11550  }
11551  } // here if checked all possible exits without success
11552  ShowMessage(
11553  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11554  Utilities->CallLogPop(133);
11555  return(false);
11556  }
11557 // dealt above with LastPrefDirElement being the start element (which can be points)
11558 
11559  if((PrefDirVector.at(LastElementNumber(13)).TrackType == Points) && (PrefDirVector.at(LastElementNumber(14)).Config[PrefDirVector.at(LastElementNumber(15))
11560  .ELinkPos] == Lead)) // leading point
11561  {
11562  if(PrefDirVector.at(LastElementNumber(16)).Conn[1] == TrackVectorPosition) // found it next to XLinkPos = 1
11563  {
11564  PrefDirVector.at(LastElementNumber(17)).XLinkPos = 1;
11565  PrefDirVector.at(LastElementNumber(18)).XLink = PrefDirVector.at(LastElementNumber(19)).Link[1];
11566  // can't be buffers or gap if points
11567  PrefDirVector.at(LastElementNumber(20)).CheckCount++;
11568  PrefDirVector.at(LastElementNumber(21)).CheckCount++;
11569  TempTrackElement = PrefDirVector.at(LastElementNumber(22));
11570  SearchVector.clear();
11571  if(SearchForPrefDir(3, TempTrackElement, 1, TrackVectorPosition)) // bound to return true
11572  {
11574  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11575  {
11576  FinishElement = true;
11577  }
11578  Utilities->CallLogPop(134);
11579  return(true);
11580  }
11581  }
11582  if(PrefDirVector.at(LastElementNumber(23)).Conn[3] == TrackVectorPosition) // found it next to XLinkPos = 3
11583  {
11584  PrefDirVector.at(LastElementNumber(24)).XLinkPos = 3;
11585  PrefDirVector.at(LastElementNumber(25)).XLink = PrefDirVector.at(LastElementNumber(26)).Link[3];
11586  PrefDirVector.at(LastElementNumber(27)).CheckCount++;
11587  PrefDirVector.at(LastElementNumber(28)).CheckCount++;
11588  TempTrackElement = PrefDirVector.at(LastElementNumber(29));
11589  SearchVector.clear();
11590  if(SearchForPrefDir(4, TempTrackElement, 3, TrackVectorPosition)) // bound to return true
11591  {
11593  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11594  {
11595  FinishElement = true;
11596  }
11597  Utilities->CallLogPop(135);
11598  return(true);
11599  }
11600  }
11601 // above dealt with immediate finds for leading point,
11602 // now deal with ordinary searches for leading point
11603  PrefDirVector.at(LastElementNumber(30)).XLinkPos = 1;
11604  PrefDirVector.at(LastElementNumber(31)).XLink = PrefDirVector.at(LastElementNumber(32)).Link[1];
11605  PrefDirVector.at(LastElementNumber(33)).CheckCount++;
11606  PrefDirVector.at(LastElementNumber(34)).CheckCount++;
11607  TempTrackElement = PrefDirVector.at(LastElementNumber(35));
11608  SearchVector.clear();
11609  if(SearchForPrefDir(5, TempTrackElement, 1, TrackVectorPosition))
11610  {
11612  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11613  {
11614  FinishElement = true;
11615  }
11616  Utilities->CallLogPop(136);
11617  return(true);
11618  }
11619  PrefDirVector.at(LastElementNumber(36)).XLinkPos = 3;
11620  PrefDirVector.at(LastElementNumber(37)).XLink = PrefDirVector.at(LastElementNumber(38)).Link[3];
11621  // note that CheckCount already increased to allow for XLinkPos & XLink
11622  TempTrackElement = PrefDirVector.at(LastElementNumber(39));
11623  SearchVector.clear();
11624  if(SearchForPrefDir(6, TempTrackElement, 3, TrackVectorPosition))
11625  {
11627  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11628  {
11629  FinishElement = true;
11630  }
11631  Utilities->CallLogPop(137);
11632  return(true);
11633  }
11634 // here if failed to find match for leading point
11635  PrefDirVector.at(LastElementNumber(69)).CheckCount--; // to removed the earlier increments for XLinkPos & XLink
11636  PrefDirVector.at(LastElementNumber(70)).CheckCount--;
11637  ShowMessage(
11638  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11639  Utilities->CallLogPop(138);
11640  return(false);
11641  }
11642 // leading point fully dealt with above
11643 // here with an ordinary element, just do an ordinary search - no need to search for an immediate find
11644 // separately as covered in ordinary search.
11645 
11646  TempTrackElement = PrefDirVector.at(LastElementNumber(40));
11647  SearchVector.clear();
11648 // no need to check for valid XLinkPos as not start element and not end element or would not reach here
11649  if(SearchForPrefDir(7, TempTrackElement, PrefDirVector.at(LastElementNumber(41)).XLinkPos, TrackVectorPosition))
11650  {
11652  if((TrackElement.TrackType == Buffers) || (TrackElement.TrackType == Continuation))
11653  {
11654  FinishElement = true;
11655  }
11656  Utilities->CallLogPop(139);
11657  return(true);
11658  }
11659  ShowMessage(
11660  "Unable to find a route to the selected element - may be unreachable, too far ahead, or invalid. Try selecting an end point closer to the start point.");
11661  Utilities->CallLogPop(140);
11662  return(false); // failed to find required element
11663 }
11664 
11665 // ---------------------------------------------------------------------------
11666 
11667 bool TOnePrefDir::SearchForPrefDir(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition)
11668 /*
11669  Enter with CurrentTrackElement stored in the PrefDirVector, XLinkPos set to the link
11670  to search on, & SearchVector cleared unless entered recursively. Function is a continuous loop that
11671  exits when find required element (returns true) or reaches a buffer or continuation or otherwise fails a search condition (returns false).
11672  Keep a count of entries in SearchVector during the current function call, so that this number can be
11673  erased for an unproductive branch search.
11674  Create a NextTrackElement from Current & XLinkPos as far as possible, & check if found required
11675  element. If so save it & return true. If not check if buffer, continuation, or earlier position
11676  in SearchVector or PrefDirVector, & if so erase all searchvector & return false. If OK check if a leading point and
11677  if so do up to 2 recursive searches for the 2 exits. If fail on both erase searchvector & return false.
11678  If not any of above, store element in searchvector, set the new current element values from the
11679  SearchElement, then go back to the while loop for the next step in the search.
11680 */
11681 {
11682  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPrefDir," + CurrentTrackElement.LogTrack(13) + "," +
11683  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition));
11684  int VectorCount = 0;
11685 
11686  while(true)
11687  {
11688  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
11689  {
11690  for(int x = 0; x < VectorCount; x++)
11691  {
11692  SearchVector.erase(SearchVector.end() - 1);
11693  }
11694  Utilities->CallLogPop(141);
11695  return(false);
11696  }
11697  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
11698  TTrackElement NextTrackElement = Track->TrackElementAt(74, NextPosition);
11699  TPrefDirElement SearchElement(NextTrackElement);
11700  SearchElement.TrackVectorPosition = NextPosition;
11701  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
11702  SearchElement.ELinkPos = NextELinkPos;
11703  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
11704  int NextXLinkPos;
11705  if(SearchElement.ELinkPos == 0)
11706  {
11707  NextXLinkPos = 1;
11708  }
11709  if(SearchElement.ELinkPos == 1)
11710  {
11711  NextXLinkPos = 0;
11712  }
11713  if(SearchElement.ELinkPos == 2)
11714  {
11715  NextXLinkPos = 3;
11716  }
11717  if(SearchElement.ELinkPos == 3)
11718  {
11719  NextXLinkPos = 2;
11720  }
11721  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
11722  {
11723  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
11724  // but may be buffers, continuation or gap
11725  SearchElement.XLinkPos = NextXLinkPos;
11726  }
11727 // can't set XLink or XLinkPos yet if the element is a leading point.
11728 // check if found it
11729  if(SearchElement.TrackVectorPosition == RequiredPosition)
11730  {
11731  SearchVector.push_back(SearchElement); // XLink & XLinkPos won't be set if a leading point
11732  VectorCount++; // not really needed but include for tidyness
11733  TotalSearchCount++;
11734  Utilities->CallLogPop(142);
11735  return(true);
11736  }
11737 // check if PrefDirVector > 200 and if so reject further searches (to avoid possible problems in converting
11738 // very long vectors) - warning given in ConvertPrefDirSearchVector, though can still add elements one
11739 // at a time - drop this
11740 /*
11741  if(PrefDirVector.size() > 200)
11742  {
11743  for(int x=0;x<VectorCount;x++) SearchVector.erase(SearchVector.end() - 1);
11744  Utilities->CallLogPop(1419);
11745  return false;
11746  }
11747 */
11748 // check if a buffer or continuation
11749  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
11750  {
11751  for(int x = 0; x < VectorCount; x++)
11752  {
11753  SearchVector.erase(SearchVector.end() - 1);
11754  }
11755  Utilities->CallLogPop(143);
11756  return(false);
11757  }
11758 // check if reached an earlier position on search PrefDir with same entry value
11759  for(unsigned int x = 0; x < SearchVector.size(); x++)
11760  {
11761  if((SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition) && (SearchElement.ELink == SearchVector.at(x).ELink))
11762  {
11763  for(int x = 0; x < VectorCount; x++)
11764  {
11765  SearchVector.erase(SearchVector.end() - 1);
11766  }
11767  Utilities->CallLogPop(144);
11768  return(false);
11769  }
11770  }
11771 // check if reached an earlier position in the PrefDirVector with same entry value (without this can keep adding entries
11772 // to PrefDir4MultiMap, and since only 4 are searched an error can occur)
11773  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
11774  {
11775  if((SearchElement.TrackVectorPosition == PrefDirVector.at(x).TrackVectorPosition) && (SearchElement.ELink == PrefDirVector.at(x).ELink))
11776  {
11777  for(int x = 0; x < VectorCount; x++)
11778  {
11779  SearchVector.erase(SearchVector.end() - 1);
11780  }
11781  Utilities->CallLogPop(1417);
11782  return(false);
11783  }
11784  }
11785 
11786 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
11787 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
11788 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
11790  {
11791  for(int x = 0; x < VectorCount; x++)
11792  {
11793  SearchVector.erase(SearchVector.end() - 1);
11794  }
11795  Utilities->CallLogPop(1691);
11796  return(false);
11797  }
11798 // check if SearchVector reached 150, and if so reject, to save time in searching for PrefDirs
11799  if(SearchVector.size() > 150)
11800  {
11801  for(int x = 0; x < VectorCount; x++)
11802  {
11803  SearchVector.erase(SearchVector.end() - 1);
11804  }
11805  Utilities->CallLogPop(1418);
11806  return(false);
11807  }
11808 // check if reached a leading point
11809  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
11810  {
11811 // push element with XLink set to position [1]
11812  SearchElement.XLink = SearchElement.Link[1];
11813  SearchElement.XLinkPos = 1;
11814  SearchVector.push_back(SearchElement);
11815  VectorCount++;
11816  TotalSearchCount++;
11817  // recursive search at XLinkPos of 1 (i.e. 1st trailing exit)
11818  // Note that have to use a TTrackElement in the recursive search, so SearchElement
11819  // can't be used. NextTrackElement is the corresponding TTrackElement.
11820  if(SearchForPrefDir(8, NextTrackElement, 1, RequiredPosition))
11821  {
11822  Utilities->CallLogPop(145);
11823  return(true);
11824  }
11825  else
11826  {
11827 // remove leading point with XLinkPos [1]
11828  SearchVector.erase(SearchVector.end() - 1);
11829  VectorCount--;
11830 // push element with XLink set to position [3]
11831  SearchElement.XLink = SearchElement.Link[3];
11832  SearchElement.XLinkPos = 3;
11833  SearchVector.push_back(SearchElement);
11834  VectorCount++;
11835  TotalSearchCount++;
11836 // recursive search at XLinkPos of 3 (i.e. 2nd trailing exit)
11837  if(SearchForPrefDir(9, NextTrackElement, 3, RequiredPosition))
11838  {
11839  Utilities->CallLogPop(146);
11840  return(true);
11841  }
11842  else
11843  {
11844  for(int x = 0; x < VectorCount; x++)
11845  {
11846  SearchVector.erase(SearchVector.end() - 1);
11847  }
11848  Utilities->CallLogPop(147);
11849  return(false);
11850  }
11851  }
11852  } // if leading point
11853 
11854 // here if ordinary element, push it, inc vector & update CurrentTrackElement
11855 // ready for next element on PrefDir
11856  SearchVector.push_back(SearchElement);
11857  VectorCount++;
11858  TotalSearchCount++;
11859  XLinkPos = NextXLinkPos;
11860  CurrentTrackElement = SearchElement;
11861  } // while(true)
11862 }
11863 
11864 // ---------------------------------------------------------------------------
11865 
11867 /*
11868  Enter with SearchVector established. This contains ELink + Pos, XLink + Pos, & TrackVectorPosition
11869  for each element on the search PrefDir, though if the last element is a leading point
11870  then the final XLink won't be set.
11871  Note also that the last element in the PrefDirVector (as opposed to the searchvector) may not have its ELink set (if it was the start)
11872  nor its XLink set (if it was the start or a leading point), so these are checked first and together with EXNumber set as necessary.
11873  The remaining PrefDirVector elements are then set from the searchvector & checkcount keeps pace as values are added.
11874 */
11875 {
11876  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertPrefDirSearchVector");
11877  if(SearchVector.size() == 0)
11878  {
11879  throw Exception("Error, SearchVector empty");
11880  }
11881 // get first SearchElement in order to set last PrefDirelement
11882  TPrefDirElement SearchElement = SearchVector.at(0);
11883 
11884 // set last PrefDir element XLink & ELink values if not already set
11885 // ELink & XLink not set if was first element in PrefDir; XLink also not set if was a leading point
11886  for(int x = 0; x < 4; x++)
11887  {
11888  if(PrefDirVector.at(LastElementNumber(42)).Conn[x] == SearchElement.TrackVectorPosition)
11889  {
11890  if(PrefDirVector.at(LastElementNumber(43)).XLink == -1) // i.e. not set
11891  {
11892  PrefDirVector.at(LastElementNumber(44)).XLink = PrefDirVector.at(LastElementNumber(45)).Link[x];
11893  PrefDirVector.at(LastElementNumber(46)).XLinkPos = x;
11894  PrefDirVector.at(LastElementNumber(47)).CheckCount++;
11895  PrefDirVector.at(LastElementNumber(48)).CheckCount++;
11896  }
11897  int ELinkPos;
11898  if(PrefDirVector.at(LastElementNumber(49)).XLinkPos == 0)
11899  {
11900  ELinkPos = 1; // use actual value rather than 'x' as may be a gap
11901  }
11902  // with both ends linked to 1st searchvector element, & if XLink was set then x may not correspond
11903  if(PrefDirVector.at(LastElementNumber(50)).XLinkPos == 1)
11904  {
11905  ELinkPos = 0;
11906  }
11907  if(PrefDirVector.at(LastElementNumber(51)).XLinkPos == 2)
11908  {
11909  ELinkPos = 3;
11910  }
11911  if(PrefDirVector.at(LastElementNumber(52)).XLinkPos == 3)
11912  {
11913  ELinkPos = 2;
11914  }
11915  if(PrefDirVector.at(LastElementNumber(53)).ELink == -1) // because was start element
11916  {
11917  PrefDirVector.at(LastElementNumber(54)).ELink = PrefDirVector.at(LastElementNumber(55)).Link[ELinkPos];
11918  PrefDirVector.at(LastElementNumber(56)).ELinkPos = ELinkPos;
11919  PrefDirVector.at(LastElementNumber(57)).CheckCount++;
11920  PrefDirVector.at(LastElementNumber(58)).CheckCount++;
11921  }
11922  break; // no point going any further
11923  }
11924  }
11925 // set EXNumber for last PrefDir element, unless already set
11926 // won't be set if was first element or a leading point
11927  if(PrefDirVector.at(LastElementNumber(59)).EXNumber == -1)
11928  {
11929 /* The order for entries & exits is as follows (1st no = entry, 2nd = exit):-
11930  int EXArray[32][2] = {
11931  {4,6},{2,8}, //horizontal & vertical
11932  {2,4},{6,2},{8,6},{4,8}, //sharp curves
11933  {1,6},{3,8},{9,4},{7,2},{1,8},{3,4},{9,2},{7,6}, //loose curves
11934  {1,9},{3,7} //forward & reverse diagonals
11935 */
11936 
11937  if(!(PrefDirVector.at(LastElementNumber(60)).EntryExitNumber()))
11938  {
11939  throw Exception("Error in EntryExitNumber 1");
11940  }
11941  PrefDirVector.at(LastElementNumber(61)).EXGraphicPtr = PrefDirVector.at(LastElementNumber(62)).GetPrefDirGraphicPtr();
11942  PrefDirVector.at(LastElementNumber(63)).EntryDirectionGraphicPtr = PrefDirVector.at(LastElementNumber(64)).GetDirectionPrefDirGraphicPtr();
11943  PrefDirVector.at(LastElementNumber(65)).CheckCount++;
11944  }
11945 // Last PrefDir element now complete
11946 
11947 // construct remaining PrefDir elements from searchvector
11948  for(unsigned int x = 0; x < SearchVector.size(); x++)
11949  {
11950  SearchElement = SearchVector.at(x);
11951  TPrefDirElement PrefDirElement(Track->TrackElementAt(75, SearchElement.TrackVectorPosition));
11952  PrefDirElement.TrackVectorPosition = SearchElement.TrackVectorPosition;
11953  PrefDirElement.ELink = SearchElement.ELink;
11954  PrefDirElement.ELinkPos = SearchElement.ELinkPos;
11955  PrefDirElement.XLink = SearchElement.XLink;
11956  PrefDirElement.XLinkPos = SearchElement.XLinkPos;
11957 // if XLink & XLinkPos not set don't account for them in CheckCount
11958  if(PrefDirElement.XLink == -1)
11959  {
11960  PrefDirElement.CheckCount = 6; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11961  }
11962  // & TrackVectorPosition
11963  else
11964  {
11965  PrefDirElement.CheckCount = 8; // Hloc, VLoc, SpeedTag, ELink, ELinkPos,
11966  }
11967  // XLink, XLinkPos, TrackVectorPosition
11968 
11969 // set EXNumber (can't set EXNumber if XLink not set - if finished on a leading point
11970  if(PrefDirElement.XLink != -1)
11971  {
11972  if(!(PrefDirElement.EntryExitNumber()))
11973  {
11974  throw Exception("Error in EntryExitNumber 2");
11975  }
11976  PrefDirElement.EXGraphicPtr = PrefDirElement.GetPrefDirGraphicPtr();
11977  PrefDirElement.EntryDirectionGraphicPtr = PrefDirElement.GetDirectionPrefDirGraphicPtr();
11978  PrefDirElement.CheckCount++;
11979  // all values now incorporated if not a leading point
11980  }
11981 // store PrefDir element
11982  StorePrefDirElement(2, PrefDirElement);
11983  }
11984 // Can now validate if PrefDir finished, i.e. if buffers or continuation, else validate when 'AddPrefDir' button pressed
11985  if((LastElementPtr(0)->TrackType == Buffers) || (LastElementPtr(1)->TrackType == Continuation))
11986  {
11987  if(ValidatePrefDir(2))
11988  {
11989  ;
11990  } // error messages given within function
11991 
11992  }
11994 /* drop this, check dropped from search
11995  if(PrefDirVector.size() > 200)
11996  {
11997  ShowMessage("The selected track segment is becoming too long, until it is accepted further elements can only be added one at a time");
11998  }
11999 */
12000  Utilities->CallLogPop(148);
12001 }
12002 
12003 // ---------------------------------------------------------------------------
12004 
12005 bool TOnePrefDir::EndPossible(int Caller, bool &LeadingPoints)
12006 /*
12007  Return true if selected element is valid as a PrefDir end element, i.e. isn't leading points,
12008  and PrefDir isn't one element long. Used to enable the AddPrefDirButton during PrefDir building.
12009 */
12010 {
12011  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EndPossible");
12012  LeadingPoints = false;
12013  if(PrefDirVector.empty())
12014  {
12015  Utilities->CallLogPop(1786);
12016  return(false); // should never be empty but allow for it for safety
12017  }
12018  if(PrefDirVector.size() == 1)
12019  {
12020  Utilities->CallLogPop(149);
12021  return(false); // can't end if only one element
12022  }
12023 /*
12024  if((PrefDirVector.at(LastElementNumber()).TrackType != Points) &&
12025  (PrefDirVector.at(LastElementNumber()).TrackType != Crossover))
12026  {
12027  Utilities->CallLogPop(150);
12028  return true;
12029  }
12030 */
12031 // allow for anything but leading points
12032  if((PrefDirVector.at(LastElementNumber(66)).TrackType != Points) || (PrefDirVector.at(LastElementNumber(67)).ELinkPos == 1) ||
12033  (PrefDirVector.at(LastElementNumber(71)).ELinkPos == 3))
12034  {
12035  Utilities->CallLogPop(1776);
12036  return(true);
12037  }
12038  else
12039  {
12040  LeadingPoints = true;
12041  Utilities->CallLogPop(151);
12042  return(false);
12043  }
12044 }
12045 
12046 // ---------------------------------------------------------------------------
12047 
12049 /*
12050  Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default values,
12051  and that every element is connected to the next element
12052 */
12053 {
12054  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ValidatePrefDir");
12055  int Position;
12056  AnsiString ErrorString;
12057  bool Error = false;
12058 
12059  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12060  {
12061  if(PrefDirVector.at(x).HLoc == -2000000000)
12062  {
12063  Error = true;
12064  ErrorString = "HLoc";
12065  Position = x;
12066  }
12067  if(PrefDirVector.at(x).VLoc == -2000000000)
12068  {
12069  Error = true;
12070  ErrorString = "VLoc";
12071  Position = x;
12072  }
12073  if(PrefDirVector.at(x).ELink == -1)
12074  {
12075  Error = true;
12076  ErrorString = "ELink";
12077  Position = x;
12078  }
12079  if(PrefDirVector.at(x).ELinkPos == -1)
12080  {
12081  Error = true;
12082  ErrorString = "ELinkPos";
12083  Position = x;
12084  }
12085  if(PrefDirVector.at(x).XLink == -1)
12086  {
12087  Error = true;
12088  ErrorString = "XLink";
12089  Position = x;
12090  }
12091  if(PrefDirVector.at(x).XLinkPos == -1)
12092  {
12093  Error = true;
12094  ErrorString = "XLinkPos";
12095  Position = x;
12096  }
12097  if(PrefDirVector.at(x).SpeedTag == 0)
12098  {
12099  Error = true;
12100  ErrorString = "Tag";
12101  Position = x;
12102  }
12103  if(PrefDirVector.at(x).TrackVectorPosition == -1)
12104  {
12105  Error = true;
12106  ErrorString = "TrackVectorPosition";
12107  Position = x;
12108  }
12109  if(PrefDirVector.at(x).EXNumber == -1)
12110  {
12111  Error = true;
12112  ErrorString = "EXNumber";
12113  Position = x;
12114  }
12115  if(PrefDirVector.at(x).CheckCount != 9)
12116  // HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink, ELinkPos, XLink, XLinkPos & EXNumber
12117  {
12118  Error = true;
12119  ErrorString = "CheckCount";
12120  Position = x;
12121  }
12122 // extra checks
12123  if(PrefDirVector.at(x).EXGraphicPtr == 0)
12124  {
12125  Error = true;
12126  ErrorString = "EntryGraphicPtr";
12127  Position = x;
12128  }
12129  if(PrefDirVector.at(x).EntryDirectionGraphicPtr == 0)
12130  {
12131  Error = true;
12132  ErrorString = "EntryDirectionGraphicPtr";
12133  Position = x;
12134  }
12135 // end of extra checks
12136  if(x > 0)
12137  {
12138  if(PrefDirVector.at(x - 1).Conn[PrefDirVector.at(x - 1).XLinkPos] != PrefDirVector.at(x).TrackVectorPosition)
12139  {
12140  Error = true;
12141  ErrorString = "Last XLink not connected to this element";
12142  Position = x;
12143  }
12144  }
12145  }
12146  if(Error)
12147  {
12148  throw Exception("Error at " + AnsiString(Position) + " " + ErrorString);
12149  }
12150  else
12151  {
12152  Utilities->CallLogPop(153);
12153  return(true);
12154  }
12155 }
12156 
12157 // ---------------------------------------------------------------------------
12158 
12159 bool TOnePrefDir::GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
12160 /*
12161  This is only called during PrefDir build or distance setting. It truncates at & including the first element in the PrefDir vector
12162  that matches H & V. After the truncate the final element of the remaining PrefDir has its data members reset
12163  to the same defaults as would be the case if the PrefDir had been built up to that point - i.e. for first element
12164  or a leading point.
12165 */
12166 {
12167  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPrefDirTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc));
12168  for(unsigned int x = 0; x < (PrefDirVector.size()); x++)
12169  {
12170  if((PrefDirVector.at(x).HLoc == HLoc) && (PrefDirVector.at(x).VLoc == VLoc))
12171  {
12172  for(int PrefDirVecPos = (PrefDirVector.size() - 1); PrefDirVecPos >= (int)x; PrefDirVecPos--) // has to be int or will underflow at x==0
12173  {
12174  ErasePrefDirElementAt(1, PrefDirVecPos);
12175  }
12176  if(PrefDirVector.size() == 0)
12177  {
12178  Utilities->CallLogPop(154);
12179  return(true);
12180  }
12181  if(PrefDirVector.size() == 1)
12182  {
12183  PrefDirVector.at(x - 1).ELinkPos = -1;
12184  PrefDirVector.at(x - 1).ELink = -1;
12185  PrefDirVector.at(x - 1).XLinkPos = -1;
12186  PrefDirVector.at(x - 1).XLink = -1;
12187  PrefDirVector.at(x - 1).EXNumber = -1;
12188  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12189  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12190  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 5;
12191  Utilities->CallLogPop(155);
12192  return(true);
12193  }
12194  // here with truncate element not first element, so ELink & ELinkPos set
12195  // unset XLink & Pos if a leading point
12196  if(PrefDirVector.at(x - 1).Config[PrefDirVector.at(x - 1).ELinkPos] == Lead)
12197  {
12198  PrefDirVector.at(x - 1).XLinkPos = -1;
12199  PrefDirVector.at(x - 1).XLink = -1;
12200  PrefDirVector.at(x - 1).EXNumber = -1;
12201  PrefDirVector.at(x - 1).EXGraphicPtr = 0;
12202  PrefDirVector.at(x - 1).EntryDirectionGraphicPtr = 0;
12203  PrefDirVector.at(x - 1).CheckCount = PrefDirVector.at(x - 1).CheckCount - 3;
12204  Utilities->CallLogPop(156);
12205  return(true);
12206  }
12207  Utilities->CallLogPop(157);
12208  return(true);
12209  }
12210  }
12211  Utilities->CallLogPop(158);
12212  return(false);
12213 }
12214 
12215 // ---------------------------------------------------------------------------
12216 
12217 void TOnePrefDir::PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp)
12218 const // PrefDirRoute = PrefDircall or routecall for PrefDir or route; true for BuildingPrefDir
12219 /*
12220  PrefDir and route track marker, including direction markers. Function used for both PrefDirs (PrefDirRoute == PrefDirCall) and routes
12221  (PrefDirRoute == RouteCall). The graphics for marker colours and direction are already stored in all PrefDirElements in
12222  TOnePrefDir and TOneRoute, and this function is called to display them, all in the case of a PrefDir, but for a route only the
12223  first and last elements have direction markers. No markers are displayed if a train is present on an element. Also no
12224  display if EXGraphicPtr not set. If building a PrefDir (BuildingPrefDir true) then the start and end rectangles are also
12225  displayed.
12226 */
12227 {
12228  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PrefDirMarker," + AnsiString(PrefDirRoute) + "," +
12229  AnsiString((short)BuildingPrefDir));
12230  int HPos, VPos;
12231 
12232  if(PrefDirSize() == 0)
12233  {
12234  Utilities->CallLogPop(159);
12235  return;
12236  }
12237  for(unsigned int x = 0; x < PrefDirSize(); x++)
12238  {
12239  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
12240 // if(Track->TrackElementAt(76, TempPrefDirElement.TrackVectorPosition).TrainIDOnElement > -1) continue;
12241 // don't plot route element if train present - dropped above as train departing only replotted the part of the route
12242 // that the train was on. Ensure though that whenever plot a route replot trains after else route will overwrite train
12243  // without the above, if route replotted in ClearandRebuildRailway when train is straddling 3 elements
12244  // and before the next train update, then the route element corresponding to the LagElement will be plotted,
12245  // only the front half of which will be overplotted by the back of the train, then when the train is
12246  // updated the route image will remain plotted and stay on screen until a later ClearandRebuildRailway
12247  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
12248  {
12249  Disp->PlotOutput(12, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EXGraphicPtr);
12250  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == PrefDirCall)) // PrefDir
12251  {
12252  Disp->PlotOutput(13, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12253  }
12254  else if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && (PrefDirRoute == RouteCall) && PrefDirSize() > 1)
12255  // Route, no direction if a single element
12256  {
12257  if(x == 0)
12258  {
12259  Disp->PlotOutput(14, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12260  }
12261  if(x == (PrefDirSize() - 1))
12262  {
12263  Disp->PlotOutput(15, (TempPrefDirElement.HLoc * 16), (TempPrefDirElement.VLoc * 16), TempPrefDirElement.EntryDirectionGraphicPtr);
12264  }
12265  }
12266  }
12267  }
12268 
12269 // set start & end element colours if building a PrefDir
12270  if((PrefDirRoute == PrefDirCall) && BuildingPrefDir)
12271  {
12272  HPos = GetFixedPrefDirElementAt(4, 0).HLoc * 16;
12273  VPos = GetFixedPrefDirElementAt(5, 0).VLoc * 16;
12274  Disp->Rectangle(1, HPos, VPos, clB0G0R5, 2, 2); // medium red rectangle
12275  // set last element colour
12276  if(PrefDirSize() > 1)
12277  {
12278  unsigned int LatestPos = PrefDirSize() - 1;
12279  HPos = GetFixedPrefDirElementAt(6, LatestPos).HLoc * 16;
12280  VPos = GetFixedPrefDirElementAt(7, LatestPos).VLoc * 16;
12281  Disp->Rectangle(2, HPos, VPos, clB5G0R0, 4, 2); // smaller blue rectangle
12282  }
12283  }
12284  Disp->Update();
12285  Utilities->CallLogPop(160);
12286 }
12287 
12288 // ---------------------------------------------------------------------------
12289 
12291 /*
12292  Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green for bidirectional
12293  Colours taken from the route colours. Plot red first so green overwrites for bidirectional points.
12294 */
12295 {
12296  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EveryPrefDirMarker");
12297  if(PrefDirSize() == 0)
12298  {
12299  Utilities->CallLogPop(1547);
12300  return;
12301  }
12302  int H, V, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12303  bool FoundFlag;
12305  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
12306 
12307  while(MMIT != PrefDir4MultiMap.end())
12308  {
12309  H = MMIT->first.first;
12310  V = MMIT->first.second;
12311  GetVectorPositionsFromPrefDir4MultiMap(6, H, V, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12312  // always found in order, any missing have PrefDirPosx == -1
12313  if(PrefDirPos0 > -1)
12314  {
12315  PrefDirElement0 = GetFixedPrefDirElementAt(170, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
12316  }
12317  if(PrefDirPos1 > -1)
12318  {
12319  PrefDirElement1 = GetFixedPrefDirElementAt(171, PrefDirPos1);
12320  }
12321  if(PrefDirPos2 > -1)
12322  {
12323  PrefDirElement2 = GetFixedPrefDirElementAt(172, PrefDirPos2);
12324  }
12325  if(PrefDirPos3 > -1)
12326  {
12327  PrefDirElement3 = GetFixedPrefDirElementAt(173, PrefDirPos3);
12328  }
12329  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
12330  {
12331  // need to plot all 4 in order to obtain all the direction graphics
12332  Disp->PlotOutput(77, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12333  Disp->PlotOutput(78, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12334  Disp->PlotOutput(79, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12335  Disp->PlotOutput(80, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12336  Disp->PlotOutput(81, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12337  Disp->PlotOutput(82, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12338  Disp->PlotOutput(83, (H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
12339  Disp->PlotOutput(84, (H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
12340  MMIT++;
12341  MMIT++;
12342  MMIT++;
12343  MMIT++;
12344  }
12345  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
12346  {
12347  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12348  {
12349  // 0 & 1 constitute the bidirectional PrefDir
12350  Disp->PlotOutput(89, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
12351  Disp->PlotOutput(90, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
12352  Disp->PlotOutput(85, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12353  Disp->PlotOutput(86, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12354  Disp->PlotOutput(87, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12355  Disp->PlotOutput(88, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12356  MMIT++;
12357  MMIT++;
12358  MMIT++;
12359  }
12360  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
12361  {
12362  // 0 & 2 constitute the bidirectional PrefDir
12363  Disp->PlotOutput(95, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12364  Disp->PlotOutput(96, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12365  Disp->PlotOutput(91, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12366  Disp->PlotOutput(92, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12367  Disp->PlotOutput(93, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12368  Disp->PlotOutput(94, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12369  MMIT++;
12370  MMIT++;
12371  MMIT++;
12372  }
12373  else
12374  {
12375  // 1 & 2 constitute the bidirectional PrefDir
12376  Disp->PlotOutput(101, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12377  Disp->PlotOutput(102, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12378  Disp->PlotOutput(97, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12379  Disp->PlotOutput(98, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12380  Disp->PlotOutput(99, (H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
12381  Disp->PlotOutput(100, (H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
12382  MMIT++;
12383  MMIT++;
12384  MMIT++;
12385  }
12386  }
12387  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
12388  {
12389  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
12390  {
12391  // 0 & 1 constitute the bidirectional PrefDir
12392  Disp->PlotOutput(103, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
12393  Disp->PlotOutput(104, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
12394  Disp->PlotOutput(105, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
12395  Disp->PlotOutput(106, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
12396  MMIT++;
12397  MMIT++;
12398  }
12399  else
12400  {
12401  // 2 unidirectional PrefDirs
12402  Disp->PlotOutput(107, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12403  Disp->PlotOutput(108, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12404  Disp->PlotOutput(109, (H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
12405  Disp->PlotOutput(110, (H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
12406  MMIT++;
12407  MMIT++;
12408  }
12409  }
12410  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
12411  {
12412  Disp->PlotOutput(111, (H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
12413  Disp->PlotOutput(112, (H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
12414  MMIT++;
12415  }
12416  }
12417  Disp->Update();
12418  Utilities->CallLogPop(1548);
12419 }
12420 
12421 // ---------------------------------------------------------------------------
12422 
12423 void TOnePrefDir::LoadOldPrefDir(int Caller, std::ifstream &VecFile)
12424 {
12425  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadOldPrefDir");
12426  int TempInt;
12427 
12428  ClearPrefDir();
12429  int NumberOfPrefDirElements = 0;
12430 
12431  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12432  for(int x = 0; x < NumberOfPrefDirElements; x++)
12433  {
12434  VecFile >> TempInt; // TrackVectorPosition
12435  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(714, TempInt));
12436  LoadPrefDirElement.TrackVectorPosition = TempInt;
12437  VecFile >> TempInt;
12438  LoadPrefDirElement.ELink = TempInt;
12439  VecFile >> TempInt;
12440  LoadPrefDirElement.ELinkPos = TempInt;
12441  VecFile >> TempInt;
12442  LoadPrefDirElement.XLink = TempInt;
12443  VecFile >> TempInt;
12444  LoadPrefDirElement.XLinkPos = TempInt;
12445  VecFile >> TempInt;
12446  LoadPrefDirElement.EXNumber = TempInt;
12447  VecFile >> TempInt;
12448  LoadPrefDirElement.CheckCount = TempInt;
12449  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12450  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12451  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12452  if(!(LoadPrefDirElement.IsARoute))
12453  {
12454  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12455  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12456  }
12457  else
12458  {
12459  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12460  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12461  LoadPrefDirElement.PrefDirRoute);
12462  }
12463  StorePrefDirElement(5, LoadPrefDirElement);
12464  Utilities->LoadFileString(VecFile); // marker
12465  }
12467  Utilities->CallLogPop(161);
12468 }
12469 
12470 // ---------------------------------------------------------------------------
12471 
12472 void TOnePrefDir::LoadPrefDir(int Caller, std::ifstream &VecFile)
12473 {
12474  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadPrefDir");
12475  int TempInt;
12476 
12477  ClearPrefDir();
12478  int NumberOfPrefDirElements = 0;
12479 
12480  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12481  for(int x = 0; x < NumberOfPrefDirElements; x++)
12482  {
12483  VecFile >> TempInt; // PrefDirVectorPosition, not used in load
12484  VecFile >> TempInt; // TrackVectorPosition
12485  TPrefDirElement LoadPrefDirElement(Track->TrackElementAt(781, TempInt)); //Loads all basic TrackElement values incl HLoc, VLoc & SpeedTag
12486  LoadPrefDirElement.TrackVectorPosition = TempInt;
12487  VecFile >> TempInt;
12488  LoadPrefDirElement.ELink = TempInt;
12489  VecFile >> TempInt;
12490  LoadPrefDirElement.ELinkPos = TempInt;
12491  VecFile >> TempInt;
12492  LoadPrefDirElement.XLink = TempInt;
12493  VecFile >> TempInt;
12494  LoadPrefDirElement.XLinkPos = TempInt;
12495  VecFile >> TempInt;
12496  LoadPrefDirElement.EXNumber = TempInt;
12497  VecFile >> TempInt;
12498  LoadPrefDirElement.CheckCount = TempInt;
12499  LoadPrefDirElement.IsARoute = Utilities->LoadFileBool(VecFile);
12500  LoadPrefDirElement.AutoSignals = Utilities->LoadFileBool(VecFile);
12501  LoadPrefDirElement.PrefDirRoute = Utilities->LoadFileBool(VecFile);
12502  if(!(LoadPrefDirElement.IsARoute))
12503  {
12504  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetPrefDirGraphicPtr();
12505  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionPrefDirGraphicPtr();
12506  }
12507  else
12508  {
12509  LoadPrefDirElement.EXGraphicPtr = LoadPrefDirElement.GetRouteGraphicPtr(LoadPrefDirElement.AutoSignals, LoadPrefDirElement.PrefDirRoute);
12510  LoadPrefDirElement.EntryDirectionGraphicPtr = LoadPrefDirElement.GetDirectionRouteGraphicPtr(LoadPrefDirElement.AutoSignals,
12511  LoadPrefDirElement.PrefDirRoute);
12512  }
12513  StorePrefDirElement(0, LoadPrefDirElement);
12514  AnsiString MarkerString = Utilities->LoadFileString(VecFile); // marker
12515  }
12517  Utilities->CallLogPop(1509);
12518 }
12519 
12520 // ---------------------------------------------------------------------------
12521 
12522 bool TOnePrefDir::CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile) // returns false if no more PrefDirs to check
12523 /*
12524  Called before PrefDir loading as part of the FileIntegrityCheck function, in case there is an error in the
12525  file. Very similar to LoadPrefDir but with value checks instead of storage in PrefDirVector.
12526 */
12527 {
12528  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckOnePrefDir");
12529  int TempInt;
12530  int NumberOfPrefDirElements = 0;
12531 
12532  NumberOfPrefDirElements = Utilities->LoadFileInt(VecFile);
12533  if((NumberOfPrefDirElements < 0) || (NumberOfPrefDirElements > 1000000))
12534  {
12535  Utilities->CallLogPop(1152);
12536  return(false);
12537  }
12538  for(int x = 0; x < NumberOfPrefDirElements; x++)
12539  {
12540  if(!Utilities->CheckFileInt(VecFile, x, x)) // vector number
12541  {
12542  Utilities->CallLogPop(1766);
12543  return(false);
12544  }
12545  VecFile >> TempInt;
12546  if((TempInt < 0) || (TempInt >= NumberOfActiveElements)) // TrackVectorPosition
12547  {
12548  Utilities->CallLogPop(163);
12549  return(false);
12550  }
12551  VecFile >> TempInt;
12552  if((TempInt < -1) || (TempInt > 9)) // ELink
12553  {
12554  Utilities->CallLogPop(162);
12555  return(false);
12556  }
12557  VecFile >> TempInt;
12558  if((TempInt < -1) || (TempInt > 3)) // ELinkPos
12559  {
12560  Utilities->CallLogPop(164);
12561  return(false);
12562  }
12563  VecFile >> TempInt;
12564  if((TempInt < -1) || (TempInt > 9)) // XLink
12565  {
12566  Utilities->CallLogPop(165);
12567  return(false);
12568  }
12569  VecFile >> TempInt;
12570  if((TempInt < -1) || (TempInt > 3)) // XLinkPos
12571  {
12572  Utilities->CallLogPop(166);
12573  return(false);
12574  }
12575  VecFile >> TempInt;
12576  if((TempInt < -1) || (TempInt > 27)) // EXNumber
12577  {
12578  Utilities->CallLogPop(167);
12579  return(false);
12580  }
12581  VecFile >> TempInt;
12582  if(TempInt != 9) // CheckCount - reduced to 11 after NextPrefDirElement dropped &
12583  // to 9 after End & Stop dropped. Leaving HLoc, VLoc, SpeedTag, TrackVectorPosition, ELink,
12584  // ELinkPos, XLink, XLinkPos & EXNumber
12585  {
12586  Utilities->CallLogPop(168);
12587  return(false);
12588  }
12589  VecFile >> TempInt;
12590  if((TempInt != 0) && (TempInt != 1)) // RouteElement
12591  {
12592  Utilities->CallLogPop(1147);
12593  return(false);
12594  }
12595  VecFile >> TempInt;
12596  if((TempInt != 0) && (TempInt != 1)) // AutoSignals
12597  {
12598  Utilities->CallLogPop(1510);
12599  return(false);
12600  }
12601  VecFile >> TempInt;
12602  if((TempInt != 0) && (TempInt != 1)) // PrefDirRoute
12603  {
12604  Utilities->CallLogPop(1148);
12605  return(false);
12606  }
12607  if(!Utilities->CheckFileStringZeroDelimiter(VecFile)) // marker
12608  {
12609  Utilities->CallLogPop(1700);
12610  return(false);
12611  }
12612  }
12613  Utilities->CallLogPop(169);
12614  return(true);
12615 }
12616 
12617 // ---------------------------------------------------------------------------
12618 
12619 void TOnePrefDir::SavePrefDirVector(int Caller, std::ofstream &VecFile)
12620 {
12621  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SavePrefDir");
12622  int NumberOfPrefDirElements = PrefDirVector.size();
12623 
12624  Utilities->SaveFileInt(VecFile, NumberOfPrefDirElements);
12625  for(int y = 0; y < NumberOfPrefDirElements; y++)
12626  {
12627  VecFile << y << '\n'; // extra
12628  VecFile << PrefDirVector.at(y).TrackVectorPosition << '\n'; //When reloaded values for HLoc, VLoc & SpeedTag are derived from the TrackElement at TrackVectorPosition
12629  VecFile << PrefDirVector.at(y).ELink << '\n'; //so all 9 critical values are set
12630  VecFile << PrefDirVector.at(y).ELinkPos << '\n';
12631  VecFile << PrefDirVector.at(y).XLink << '\n';
12632  VecFile << PrefDirVector.at(y).XLinkPos << '\n';
12633  VecFile << PrefDirVector.at(y).EXNumber << '\n';
12634  VecFile << PrefDirVector.at(y).CheckCount << '\n';
12635  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).IsARoute);
12636  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).AutoSignals);
12637  Utilities->SaveFileBool(VecFile, PrefDirVector.at(y).PrefDirRoute);
12638  if(y == (NumberOfPrefDirElements - 1)) // last element, write a longer delimiter
12639  {
12640  VecFile << "************" << '\0' << '\n'; // marker
12641  }
12642  else
12643  {
12644  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12645  }
12646  }
12647  Utilities->CallLogPop(170);
12648 }
12649 
12650 // ---------------------------------------------------------------------------
12651 
12652 void TOnePrefDir::SaveSearchVector(int Caller, std::ofstream &VecFile)
12653 {
12654  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveSearchVector");
12655  int NumberOfSearchElements = SearchVector.size();
12656 
12657  Utilities->SaveFileInt(VecFile, NumberOfSearchElements);
12658  for(int y = 0; y < NumberOfSearchElements; y++)
12659  {
12660  VecFile << y << '\n'; // extra
12661  VecFile << SearchVector.at(y).TrackVectorPosition << '\n';
12662  VecFile << SearchVector.at(y).ELink << '\n';
12663  VecFile << SearchVector.at(y).ELinkPos << '\n';
12664  VecFile << SearchVector.at(y).XLink << '\n';
12665  VecFile << SearchVector.at(y).XLinkPos << '\n';
12666  VecFile << SearchVector.at(y).EXNumber << '\n';
12667  VecFile << SearchVector.at(y).CheckCount << '\n';
12668  Utilities->SaveFileBool(VecFile, SearchVector.at(y).IsARoute);
12669  Utilities->SaveFileBool(VecFile, SearchVector.at(y).AutoSignals);
12670  Utilities->SaveFileBool(VecFile, SearchVector.at(y).PrefDirRoute);
12671  if(y == (NumberOfSearchElements - 1)) // last element, write a longer delimiter
12672  {
12673  VecFile << "************" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12674  }
12675  else
12676  {
12677  VecFile << "******" << '\0' << '\n'; // note: << doesn't write the null string terminator character automatically
12678  }
12679  }
12680  Utilities->CallLogPop(1847);
12681 }
12682 
12683 // ---------------------------------------------------------------------------
12684 
12685 void TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
12686 /*
12687  Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails
12688  erasing up to four elements (2 directions and 2 tracks for 4-entry elements).
12689 */
12690 {
12691  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",EraseFromPrefDirVectorAnd4MultiMap," + AnsiString(HLoc) + "," +
12692  AnsiString(VLoc));
12693  int VecPos = GetOnePrefDirPosition(1, HLoc, VLoc);
12694 
12695  if(VecPos > -1)
12696  {
12697  ErasePrefDirElementAt(2, VecPos); // max of 4 to be erased
12698  }
12699  else
12700  {
12701  Utilities->CallLogPop(171);
12702  return;
12703  }
12704  VecPos = GetOnePrefDirPosition(2, HLoc, VLoc);
12705  if(VecPos > -1)
12706  {
12707  ErasePrefDirElementAt(3, VecPos);
12708  }
12709  else
12710  {
12711  Utilities->CallLogPop(172);
12712  return;
12713  }
12714  VecPos = GetOnePrefDirPosition(3, HLoc, VLoc);
12715  if(VecPos > -1)
12716  {
12717  ErasePrefDirElementAt(4, VecPos);
12718  }
12719  else
12720  {
12721  Utilities->CallLogPop(173);
12722  return;
12723  }
12724  VecPos = GetOnePrefDirPosition(4, HLoc, VLoc);
12725  if(VecPos > -1)
12726  {
12727  ErasePrefDirElementAt(5, VecPos);
12728  }
12729  else
12730  {
12731  Utilities->CallLogPop(174);
12732  return;
12733  }
12734  Utilities->CallLogPop(175);
12735 }
12736 
12737 // ---------------------------------------------------------------------------
12738 /*
12739  void TOnePrefDir::EraseCorruptedElementsAfterTrackBuild()//Delete any PrefDir elements that are no longer valid
12740  //Not needed after new TrackErase (now EraseTrackElement), where blank elements aren't used
12741 
12742  When track is rebuilt any elements that are dispensed with aren't erased immediately, a blank element is put
12743  in their place so that existing linkages will be preserved. At this stage this function is called to remove
12744  any elements in PrefDirVector that correspond directly to blank track elements or that are connected to blank track
12745  elements. Finally the track is reconnected using Track->TryToConnectTrack (if won't connect then returns to
12746  AddTrackStage build mode for corrections to be made) and then EveryPrefDir->RebuildPrefDirVector() called to reset
12747  PrefDirVector to correspond to the new track layout.
12748 
12749  {
12750  Utilities->CallLog.push_back(Utilities->TimeStamp() + ",EraseCorruptedElementsAfterTrackBuild");
12751  if(PrefDirSize() == 0)
12752  {
12753  Utilities->CallLogPop(176);
12754  return;
12755  }
12756  for(int x=(PrefDirVector.size()-1);x>=0;x--)
12757  {
12758  int TV = PrefDirVector.at(x).TrackVectorPosition;
12759  int ConnELink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).ELinkPos];
12760  int ConnXLink = PrefDirVector.at(x).Conn[PrefDirVector.at(x).XLinkPos];
12761  if(Track->BlankElementAt(0, TV))
12762  {
12763  ErasePrefDirElementAt(6, x);
12764  }
12765  //if was a blankelement at x then ConnELink and ConnXLink both -1
12766  else if((ConnELink > -1) && (Track->BlankElementAt(1, ConnELink)))
12767  {
12768  ErasePrefDirElementAt(7, x);
12769  }
12770  //if both ConnELink and ConnXLink correspond to blank elements then OK, element only
12771  //needs to be erased once, but if don't use 'else' then will erase two elements
12772  //since 'x' will correspond to the element after the first erased element
12773  else if((ConnXLink > -1) && (Track->BlankElementAt(2, ConnXLink)))
12774  {
12775  ErasePrefDirElementAt(8, x);
12776  }
12777  }
12778  Utilities->CallLogPop(177);
12779  }
12780 */
12781 // ---------------------------------------------------------------------------
12782 
12783 void TOnePrefDir::ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
12784 /*
12785  This is used to add InputPrefDir's PrefDirVector to TOnePrefDir's PrefDirVector except where it already
12786  exists in TOnePrefDir. In practice it adds ConstructPrefDir to EveryPrefDir.
12787 */
12788 {
12789  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConsolidatePrefDirs");
12790  bool AlreadyPresent, FoundFlag;
12791  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
12792 
12793  for(unsigned int x = 0; x < InputPrefDir->PrefDirSize(); x++)
12794  {
12795  TPrefDirElement TempElement = InputPrefDir->PrefDirVector.at(x);
12796  GetVectorPositionsFromPrefDir4MultiMap(1, TempElement.HLoc, TempElement.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
12797  AlreadyPresent = false;
12798  if(FoundFlag)
12799  {
12800  if((PrefDirPos0 > -1) && (TempElement == GetFixedPrefDirElementAt(8, PrefDirPos0)))
12801  {
12802  AlreadyPresent = true;
12803  }
12804  if((PrefDirPos1 > -1) && (TempElement == GetFixedPrefDirElementAt(9, PrefDirPos1)))
12805  {
12806  AlreadyPresent = true;
12807  }
12808  if((PrefDirPos2 > -1) && (TempElement == GetFixedPrefDirElementAt(10, PrefDirPos2)))
12809  {
12810  AlreadyPresent = true;
12811  }
12812  if((PrefDirPos3 > -1) && (TempElement == GetFixedPrefDirElementAt(11, PrefDirPos3)))
12813  {
12814  AlreadyPresent = true;
12815  }
12816  }
12817  if(!AlreadyPresent)
12818  {
12819  StorePrefDirElement(4, TempElement);
12820  }
12821  }
12823  Utilities->CallLogPop(178);
12824 }
12825 /* earlier brute force search
12826  for(unsigned int x = 0;x<InputPrefDir->PrefDirSize();x++)
12827  {
12828  TPrefDirElement TempElement = InputPrefDir->GetFixedPrefDirElementAt(12, x);
12829  bool AlreadyPresent = false;
12830  for(unsigned int y = 0;y<PrefDirSize();y++)
12831  {
12832  if(TempElement == GetFixedPrefDirElementAt(13, y)) AlreadyPresent = true;
12833  }
12834  if(!AlreadyPresent) StorePrefDirElement(, TempElement);
12835  }
12836 */
12837 
12838 // ---------------------------------------------------------------------------
12839 
12841 /*
12842  Rebuild from Trackmap, doesn't affect PrefDir4MultiMap.
12843  After a track build, but before the track is reconnected, all invalid PrefDir elements in TOnePrefDir
12844  (i.e. in EveryPrefDir) are erased. Hence at that stage all the PrefDir elements are valid and correspond to
12845  the track elements at relevant H & V positions. However, after the track is reconnected, the TrackVector
12846  positions are likely to have changed, so this function is called to reset all the necessary connections and
12847  TrackVector positions. To be on the safe side all the TrackElement values that are additional to
12848  TFixedTrackPiece (apart from TrainIDs, these only present during operation) are reset, though the others
12849  shouldn't have changed.
12850 */
12851 {
12852  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RebuildPrefDirVector");
12853  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12854  {
12855  bool FoundFlag;
12856  int VecPos = Track->GetVectorPositionFromTrackMap(10, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12857  if(FoundFlag)
12858  {
12859  PrefDirVector.at(x).TrackVectorPosition = VecPos;
12860  PrefDirVector.at(x).LocationName = Track->TrackElementAt(78, VecPos).LocationName;
12861  PrefDirVector.at(x).ActiveTrackElementName = Track->TrackElementAt(79, VecPos).ActiveTrackElementName;
12862  PrefDirVector.at(x).ElementID = Track->TrackElementAt(80, VecPos).ElementID;
12863  PrefDirVector.at(x).Attribute = Track->TrackElementAt(81, VecPos).Attribute;
12864  for(unsigned int z = 0; z < 4; z++)
12865  {
12866  PrefDirVector.at(x).Conn[z] = Track->TrackElementAt(82, VecPos).Conn[z];
12867  PrefDirVector.at(x).ConnLinkPos[z] = Track->TrackElementAt(83, VecPos).ConnLinkPos[z];
12868  }
12869  }
12870  else
12871  {
12872  throw Exception("Error in RebuildPrefDirVector - PrefDirVector is unsafe");
12873  }
12874  }
12875  Utilities->CallLogPop(179);
12876 }
12877 
12878 // ---------------------------------------------------------------------------
12879 
12881 /*
12882  Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefDir & PrefDir4MultiMap.
12883 */
12884 {
12885  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVector");
12886  bool DiscrepancyFound = false;
12887 
12888  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12889  {
12890  bool FoundFlag;
12891  int VecPos = Track->GetVectorPositionFromTrackMap(39, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12892  if(FoundFlag)
12893  {
12894  TPrefDirElement PE = PrefDirVector.at(x);
12895  if(PE.TrackVectorPosition != VecPos)
12896  {
12897  DiscrepancyFound = true;
12898  break;
12899  }
12900  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12901  {
12902  DiscrepancyFound = true;
12903  break;
12904  }
12905  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12906  {
12907  DiscrepancyFound = true;
12908  break;
12909  }
12910  if(PE.ELink != Track->TrackElementAt(710, VecPos).Link[PE.GetELinkPos()])
12911  {
12912  DiscrepancyFound = true;
12913  break;
12914  }
12915  if(PE.XLink != Track->TrackElementAt(711, VecPos).Link[PE.GetXLinkPos()])
12916  {
12917  DiscrepancyFound = true;
12918  break;
12919  }
12920  }
12921  else
12922  {
12923  DiscrepancyFound = true;
12924  }
12925  }
12926  if(DiscrepancyFound)
12927  {
12928  ShowMessage("Discrepancies found in the preferred direction file, preferred directions will be cleared");
12929  ClearPrefDir(); // also clears multimap
12930  }
12931  Utilities->CallLogPop(1436);
12932 }
12933 
12934 // ---------------------------------------------------------------------------
12935 
12937 /*
12938  Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4MultiMap.
12939  return true for OK
12940 */
12941 {
12942  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDirAgainstTrackVectorNoMessage");
12943  bool DiscrepancyFound = false;
12944 
12945  for(unsigned int x = 0; x < PrefDirVector.size(); x++)
12946  {
12947  bool FoundFlag;
12948  int VecPos = Track->GetVectorPositionFromTrackMap(36, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc, FoundFlag);
12949  if(FoundFlag)
12950  {
12951  TPrefDirElement PE = PrefDirVector.at(x);
12952  if(PE.TrackVectorPosition != VecPos)
12953  {
12954  DiscrepancyFound = true;
12955  }
12956  if((PE.GetELinkPos() < 0) || (PE.GetELinkPos() > 3))
12957  {
12958  DiscrepancyFound = true;
12959  break;
12960  }
12961  if((PE.GetXLinkPos() < 0) || (PE.GetXLinkPos() > 3))
12962  {
12963  DiscrepancyFound = true;
12964  break;
12965  }
12966  if(PE.ELink != Track->TrackElementAt(715, VecPos).Link[PE.GetELinkPos()])
12967  {
12968  DiscrepancyFound = true;
12969  break;
12970  }
12971  if(PE.XLink != Track->TrackElementAt(716, VecPos).Link[PE.GetXLinkPos()])
12972  {
12973  DiscrepancyFound = true;
12974  break;
12975  }
12976  }
12977  else
12978  {
12979  DiscrepancyFound = true;
12980  }
12981  }
12982  Utilities->CallLogPop(1512);
12983  return(!DiscrepancyFound);
12984 }
12985 
12986 // ---------------------------------------------------------------------------
12987 
12988 void TOnePrefDir::CheckPrefDir4MultiMap(int Caller) // test
12989 /*
12990  Test function to check correspondence between PrefDirVector and PrefDir4MultiMap for each element in
12991  turn and for the overall sizes.
12992 */
12993 {
12994  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckPrefDir4MultiMap");
12995  bool FoundFlag = false;
12996  int PrefDir0, PrefDir1, PrefDir2, PrefDir3;
12997 
12998  for(unsigned int a = 0; a < PrefDirVector.size(); a++)
12999  {
13000  TPrefDirElement CheckElement = PrefDirVector.at(a);
13001  GetVectorPositionsFromPrefDir4MultiMap(2, CheckElement.HLoc, CheckElement.VLoc, FoundFlag, PrefDir0, PrefDir1, PrefDir2, PrefDir3);
13002  if(!FoundFlag)
13003  {
13004  throw Exception("CheckPrefDir4MultiMap Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
13005  " in PrefDir4MultiMap, Caller=" + (AnsiString)Caller);
13006  }
13007  if((PrefDir0 != (int)a) && (PrefDir1 != (int)a) && (PrefDir2 != (int)a) && (PrefDir3 != (int)a))
13008  {
13009  throw Exception("CheckPrefDir4MultiMap Error - MapVectorPosition failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
13010  (AnsiString)CheckElement.VLoc + " Map values=" + (AnsiString)PrefDir0 + ", " + (AnsiString)PrefDir1 + ", " + (AnsiString)PrefDir2 + ", " +
13011  (AnsiString)PrefDir3 + " PrefDirVectorPos value=" + (AnsiString)a + " Caller=" + (AnsiString)Caller);
13012  }
13013  }
13014  if(PrefDirVector.size() != PrefDir4MultiMap.size())
13015  {
13016  throw Exception("CheckPrefDir4MultiMap Error - Map Size=" + (AnsiString)PrefDirVector.size() + " PrefDirVectorSize=" + (AnsiString)PrefDirVector.size()
13017  + " Caller=" + (AnsiString)Caller);
13018  }
13019  Utilities->CallLogPop(180);
13020 }
13021 
13022 // ---------------------------------------------------------------------------
13023 
13024 void TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2,
13025  int &PrefDirPos3)
13026 /*
13027  There are up to four elements at each H & V position in the PrefDirVector - two directions per track, and up to
13028  two tracks for 4-entry elements. This function retrieves all elements that are present at a give H & V
13029  position. FoundFlag indicates whether any or none have been found, and PrefDirPos0, 1, 2 & 3 contain
13030  the PrefDirVector positions, or -1 if not present. The elements are always found in order, such that
13031  if there is only one it will be in PrefDirPos0, if two they will be in PrefDirPos0 and PrefDirPos1 and so on.
13032 */
13033 {
13034  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetVectorPositionsFromPrefDir4MultiMap," + AnsiString(HLoc) + "," +
13035  AnsiString(VLoc));
13036  THVPair PrefDirMapKeyPair;
13037 
13038  PrefDirPos0 = -1;
13039  PrefDirPos1 = -1;
13040  PrefDirPos2 = -1;
13041  PrefDirPos3 = -1;
13042  FoundFlag = false;
13043  PrefDirMapKeyPair.first = HLoc;
13044  PrefDirMapKeyPair.second = VLoc;
13045  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13046 
13047  ItPair = PrefDir4MultiMap.equal_range(PrefDirMapKeyPair);
13048  if(ItPair.first == ItPair.second) //none found
13049  {
13050  Utilities->CallLogPop(181);
13051  return;
13052  }
13053  else
13054  {
13055  FoundFlag = true;
13056  PrefDirPos0 = ItPair.first->second;
13057  ItPair.first++;
13058  if(ItPair.first == ItPair.second)
13059  {
13060  Utilities->CallLogPop(182); //only one found
13061  return;
13062  }
13063  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13064  {
13065  PrefDirPos1 = ItPair.first->second;
13066  }
13067  ItPair.first++;
13068  if(ItPair.first == ItPair.second)
13069  {
13070  Utilities->CallLogPop(183); //2 found
13071  return;
13072  }
13073  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13074  {
13075  PrefDirPos2 = ItPair.first->second;
13076  }
13077  ItPair.first++;
13078  if(ItPair.first == ItPair.second)
13079  {
13080  Utilities->CallLogPop(184); //3 found
13081  return;
13082  }
13083  if(((ItPair.first->first).first == HLoc) && ((ItPair.first->first).second == VLoc))
13084  {
13085  PrefDirPos3 = ItPair.first->second; //4 found
13086  }
13087  }
13088  Utilities->CallLogPop(185);
13089 }
13090 
13091 // ---------------------------------------------------------------------------
13092 
13093 bool TOnePrefDir::FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
13094 {
13095  // Finds a pref dir element that links to another element at given vector number and link number & position, returns true if found with linked
13096  // vector number, true if buffer or continuation with link at blank end & linked vector number = -1, or false if not found with vector number == -1
13097  try
13098  {
13099  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindLinkingPrefDir," + AnsiString(PrefDirVectorNumber)
13100  + "," + AnsiString(LinkNumberPos));
13101  bool FoundFlag;
13102  int PD0, PD1, PD2, PD3;
13103  if(PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos] > -1)
13104  {
13105  GetVectorPositionsFromPrefDir4MultiMap(14, Track->TrackElementAt(1021, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).HLoc,
13106  Track->TrackElementAt(1022, PrefDirVector.at(PrefDirVectorNumber).Conn[LinkNumberPos]).VLoc, FoundFlag,
13107  PD0, PD1, PD2, PD3);
13108  if(!FoundFlag)
13109  {
13110  Utilities->CallLogPop(2282);
13111  return(false);
13112  }
13113  if((PrefDirVector.at(PrefDirVectorNumber).TrackType == GapJump) && (LinkNumberPos == 0)) //0 is the gap position
13114  {
13115  if(PD0 > -1)
13116  {
13117  if(PrefDirVector.at(PD0).TrackType == GapJump) //links to a gap and there is a pref dir set on it, doesn't matter about the link position
13118  {
13119  LinkedPrefDirVectorNumber = PD0;
13120  Utilities->CallLogPop(2283);
13121  return(true);
13122  }
13123  }
13124  if(PD1 > -1)
13125  {
13126  if(PrefDirVector.at(PD1).TrackType == GapJump) //can only be PD0 or PD1 for a gap
13127  {
13128  LinkedPrefDirVectorNumber = PD1;
13129  Utilities->CallLogPop(2284);
13130  return(true);
13131  }
13132  }
13133  }
13134  if(PD0 > -1)
13135  {
13136  if((PrefDirVector.at(PD0).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD0).XLink == (10 - LinkNumber)))
13137  {
13138  LinkedPrefDirVectorNumber = PD0;
13139  Utilities->CallLogPop(2285);
13140  return(true);
13141  }
13142  }
13143  if(PD1 > -1)
13144  {
13145  if((PrefDirVector.at(PD1).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD1).XLink == (10 - LinkNumber)))
13146  {
13147  LinkedPrefDirVectorNumber = PD1;
13148  Utilities->CallLogPop(2286);
13149  return(true);
13150  }
13151  }
13152  if(PD2 > -1)
13153  {
13154  if((PrefDirVector.at(PD2).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD2).XLink == (10 - LinkNumber)))
13155  {
13156  LinkedPrefDirVectorNumber = PD2;
13157  Utilities->CallLogPop(2287);
13158  return(true);
13159  }
13160  }
13161  if(PD3 > -1)
13162  {
13163  if((PrefDirVector.at(PD3).ELink == (10 - LinkNumber)) || (PrefDirVector.at(PD3).XLink == (10 - LinkNumber)))
13164  {
13165  LinkedPrefDirVectorNumber = PD3;
13166  Utilities->CallLogPop(2288);
13167  return(true);
13168  }
13169  }
13170  LinkedPrefDirVectorNumber = -1;
13171  Utilities->CallLogPop(2289);
13172  return(false);
13173  }
13174  else //buffer or continuation, no link at position 0 but not a failure
13175  {
13176  LinkedPrefDirVectorNumber = -1;
13177  Utilities->CallLogPop(2290);
13178  return(true);
13179  }
13180  }
13181  catch(const Exception &e) //non error catch
13182  {
13183  LinkedPrefDirVectorNumber = -1;
13184  Utilities->CallLogPop(2291);
13185  return(false);
13186  }
13187 }
13188 
13189 // ---------------------------------------------------------------------------
13190 
13192 {
13193  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",BiDirectionalPrefDir");
13194  bool FoundFlag; //not used
13195  int PD0, PD1, PD2, PD3;
13196  //recover all PDs at the H & V of PDPtr
13197  GetVectorPositionsFromPrefDir4MultiMap(15, PDPtr->first.first, PDPtr->first.second, FoundFlag, PD0, PD1, PD2, PD3);
13198 
13199  int ELink = PrefDirVector.at(PDPtr->second).GetELink();
13200  int XLink = PrefDirVector.at(PDPtr->second).GetXLink();
13201 
13202  if(PD0 > -1) //ok if PDPtr->second == PD0 as won't find a match, same for others
13203  {
13204  if((PrefDirVector.at(PD0).GetELink() == XLink) && (PrefDirVector.at(PD0).GetXLink() == ELink))
13205  {
13206  Utilities->CallLogPop(2292);
13207  return(true);
13208  }
13209  }
13210  if(PD1 > -1)
13211  {
13212  if((PrefDirVector.at(PD1).GetELink() == XLink) && (PrefDirVector.at(PD1).GetXLink() == ELink))
13213  {
13214  Utilities->CallLogPop(2293);
13215  return(true);
13216  }
13217  }
13218  if(PD2 > -1)
13219  {
13220  if((PrefDirVector.at(PD2).GetELink() == XLink) && (PrefDirVector.at(PD2).GetXLink() == ELink))
13221  {
13222  Utilities->CallLogPop(2294);
13223  return(true);
13224  }
13225  }
13226  if(PD3 > -1)
13227  {
13228  if((PrefDirVector.at(PD3).GetELink() == XLink) && (PrefDirVector.at(PD3).GetXLink() == ELink))
13229  {
13230  Utilities->CallLogPop(2295);
13231  return(true);
13232  }
13233  }
13234  Utilities->CallLogPop(2296);
13235  return(false);
13236 }
13237 
13238 // ---------------------------------------------------------------------------
13239 
13240 void TOnePrefDir::StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
13241 /*
13242  LoadPrefDirElement is stored in both the PrefDirVector and in PrefDir4MultiMap.
13243 */
13244 {
13245  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StorePrefDirElement," + LoadPrefDirElement.LogPrefDir());
13246  PrefDirVector.push_back(LoadPrefDirElement);
13247  THVPair PrefDir4MultiMapKeyPair;
13248  TPrefDir4MultiMapEntry PrefDir4MultiMapEntry;
13249 
13250  PrefDir4MultiMapKeyPair.first = LoadPrefDirElement.HLoc;
13251  PrefDir4MultiMapKeyPair.second = LoadPrefDirElement.VLoc;
13252  PrefDir4MultiMapEntry.first = PrefDir4MultiMapKeyPair;
13253  PrefDir4MultiMapEntry.second = LastElementNumber(68);
13254  PrefDir4MultiMap.insert(PrefDir4MultiMapEntry);
13255 // CheckPrefDir4MultiMap(1);Drop here as takes too long - call it by each calling function
13256  Utilities->CallLogPop(186);
13257 }
13258 
13259 // ---------------------------------------------------------------------------
13260 
13261 void TOnePrefDir::ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
13262 /*
13263  Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNumbers in
13264  4MultiMap if they are greater than the erased value.
13265 */
13266 {
13267  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ErasePrefDirElementAt," + AnsiString(PrefDirVectorPosition));
13268  bool FoundFlag;
13269 
13270  if(!PrefDirVector.empty())
13271  {
13272  TPrefDir4MultiMapIterator EraseIt = GetExactMatchFrom4MultiMap(0, PrefDirVectorPosition, FoundFlag);
13273  if(!FoundFlag)
13274  {
13275  throw Exception("Failed to find PrefDir4MultiMap erase element");
13276  }
13277  PrefDirVector.erase(PrefDirVector.begin() + PrefDirVectorPosition);
13278  PrefDir4MultiMap.erase(EraseIt);
13279  DecrementPrefDirElementNumbersInPrefDir4MultiMap(0, PrefDirVectorPosition);
13281  }
13282  Utilities->CallLogPop(187);
13283 }
13284 
13285 // ---------------------------------------------------------------------------
13286 
13287 void TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
13288 /*
13289  Called after ErasePrefDirElementAt(int PrefDirVectorPosition) to decrement the remaining PrefDirElementNumbers in
13290  4MultiMap if they are greater than the erased value.
13291 */
13292 {
13293  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementPrefDirElementNumbersInPrefDir4MultiMap," +
13294  AnsiString(ErasedElementNumber));
13295  if(!PrefDir4MultiMap.empty())
13296  {
13297  for(TPrefDir4MultiMapIterator MapPtr = PrefDir4MultiMap.begin(); MapPtr != PrefDir4MultiMap.end(); MapPtr++)
13298  {
13299  if(MapPtr->second > ErasedElementNumber)
13300  {
13301  MapPtr->second--;
13302  }
13303  }
13304  }
13305  Utilities->CallLogPop(1450);
13306 }
13307 
13308 // ---------------------------------------------------------------------------
13309 
13310 TOnePrefDir::TPrefDir4MultiMapIterator TOnePrefDir::GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
13311 /*
13312  Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition. Used during
13313  ErasePrefDirElementAt(int PrefDirVectorPosition) to erase the relevant element in the multimap. If
13314  nothing is found this is an error but the error message is given in the calling function.
13315 */
13316 {
13317  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetExactMatchFrom4MultiMap," + AnsiString(PrefDirVectorPosition));
13318  FoundFlag = false;
13319  if(PrefDirVectorPosition >= PrefDirVector.size())
13320  {
13321  throw Exception("PrefDirVectorPosition out of range");
13322  }
13323  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(14, PrefDirVectorPosition);
13324  THVPair PrefDir4MultiMapKeyPair;
13325 
13326  PrefDir4MultiMapKeyPair.first = PrefDirElement.HLoc;
13327  PrefDir4MultiMapKeyPair.second = PrefDirElement.VLoc;
13328  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13329 
13330  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13331  if(ItPair.first == ItPair.second)
13332  {
13333  Utilities->CallLogPop(188);
13334  return(ItPair.first); // nothing found but have to return an iterator, FoundFlag indicates nothing found
13335  }
13336  else
13337  {
13338  if(ItPair.first->second == PrefDirVectorPosition)
13339  {
13340  FoundFlag = true;
13341  Utilities->CallLogPop(189);
13342  return(ItPair.first);
13343  }
13344  ItPair.first++;
13345  if(ItPair.first == ItPair.second)
13346  {
13347  Utilities->CallLogPop(190);
13348  return(ItPair.first); // nothing found
13349  }
13350  if(ItPair.first->second == PrefDirVectorPosition)
13351  {
13352  FoundFlag = true;
13353  Utilities->CallLogPop(191);
13354  return(ItPair.first);
13355  }
13356  ItPair.first++;
13357  if(ItPair.first == ItPair.second)
13358  {
13359  Utilities->CallLogPop(192);
13360  return(ItPair.first); // nothing found
13361  }
13362  if(ItPair.first->second == PrefDirVectorPosition)
13363  {
13364  FoundFlag = true;
13365  Utilities->CallLogPop(193);
13366  return(ItPair.first);
13367  }
13368  ItPair.first++;
13369  if(ItPair.first == ItPair.second)
13370  {
13371  Utilities->CallLogPop(194);
13372  return(ItPair.first); // nothing found
13373  }
13374  if(ItPair.first->second == PrefDirVectorPosition)
13375  {
13376  FoundFlag = true;
13377  Utilities->CallLogPop(195);
13378  return(ItPair.first);
13379  }
13380  }
13381  Utilities->CallLogPop(196);
13382  return(ItPair.first); // nothing found
13383 }
13384 
13385 // ---------------------------------------------------------------------------
13386 
13387 int TOnePrefDir::GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
13388 /*
13389  Although there may be up to four entries at one H & V position this function gets just one. It is
13390  used in EraseFromPrefDirVectorAnd4MultiMap by being called as many times as there are PrefDir elements
13391  at H & V.
13392 */
13393 {
13394  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetOnePrefDirPosition," + AnsiString(HLoc) + "," + AnsiString(VLoc));
13395  THVPair PrefDir4MultiMapKeyPair;
13396 
13397  PrefDir4MultiMapKeyPair.first = HLoc;
13398  PrefDir4MultiMapKeyPair.second = VLoc;
13399  std::pair<TPrefDir4MultiMapIterator, TPrefDir4MultiMapIterator>ItPair;
13400 
13401  ItPair = PrefDir4MultiMap.equal_range(PrefDir4MultiMapKeyPair);
13402  if(ItPair.first == ItPair.second) // nothing found
13403  {
13404  Utilities->CallLogPop(197);
13405  return(-1);
13406  }
13407  else
13408  {
13409  Utilities->CallLogPop(198);
13410  return(ItPair.first->second);
13411  }
13412 }
13413 
13414 // ---------------------------------------------------------------------------
13415 
13416 void TOnePrefDir::RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
13417 {
13418  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RealignAfterTrackErase," + AnsiString(ErasedTrackVectorPosition));
13419  bool ErasedFlag = false;
13420 
13421  if(ErasedTrackVectorPosition > -1) // should be in calling function but include here as a safeguard
13422  {
13423  if(PrefDirSize() == 0)
13424  {
13425  Utilities->CallLogPop(1511);
13426  return;
13427  }
13428  for(int x = (PrefDirSize() - 1); x >= 0; x--) // reverse because of erase
13429  {
13430  ErasedFlag = false;
13431  // use 'else' to ensure don't try to access an erased element
13432  if(PrefDirVector.at(x).TrackVectorPosition == ErasedTrackVectorPosition)
13433  {
13434  ErasePrefDirElementAt(11, x);
13435  ErasedFlag = true;
13436  }
13437  else if(PrefDirVector.at(x).Conn[0] == ErasedTrackVectorPosition)
13438  {
13439  ErasePrefDirElementAt(12, x);
13440  ErasedFlag = true;
13441  }
13442  else if(PrefDirVector.at(x).Conn[1] == ErasedTrackVectorPosition)
13443  {
13444  ErasePrefDirElementAt(13, x);
13445  ErasedFlag = true;
13446  }
13447  else if(PrefDirVector.at(x).Conn[2] == ErasedTrackVectorPosition)
13448  {
13449  ErasePrefDirElementAt(9, x);
13450  ErasedFlag = true;
13451  }
13452  else if(PrefDirVector.at(x).Conn[3] == ErasedTrackVectorPosition)
13453  {
13454  ErasePrefDirElementAt(10, x);
13455  ErasedFlag = true;
13456  }
13457  if(!ErasedFlag)
13458  {
13459  // don't use 'else' here as may be more than one that need decrementing
13460  if(PrefDirVector.at(x).TrackVectorPosition > ErasedTrackVectorPosition)
13461  {
13462  PrefDirVector.at(x).TrackVectorPosition--;
13463  }
13464  if(PrefDirVector.at(x).Conn[0] > ErasedTrackVectorPosition)
13465  {
13466  PrefDirVector.at(x).Conn[0]--;
13467  }
13468  if(PrefDirVector.at(x).Conn[1] > ErasedTrackVectorPosition)
13469  {
13470  PrefDirVector.at(x).Conn[1]--;
13471  }
13472  if(PrefDirVector.at(x).Conn[2] > ErasedTrackVectorPosition)
13473  {
13474  PrefDirVector.at(x).Conn[2]--;
13475  }
13476  if(PrefDirVector.at(x).Conn[3] > ErasedTrackVectorPosition)
13477  {
13478  PrefDirVector.at(x).Conn[3]--;
13479  }
13480  }
13481  }
13482  }
13483  Utilities->CallLogPop(1434);
13484 }
13485 
13486 // ---------------------------------------------------------------------------
13487 
13488 void TOnePrefDir::CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
13489 {
13490  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CalcDistanceAndSpeed");
13491  OverallDistance = 0;
13492  OverallSpeedLimit = 0;
13493  LeadingPointsAtLastElement = false;
13494  if(PrefDirSize() == 0) // shouldn't be empty when this called
13495  {
13496  Utilities->CallLogPop(1491);
13497  return;
13498  }
13499  if((LastElementPtr(21)->TrackType == Points) && (LastElementPtr(22)->ELinkPos != 1) && (LastElementPtr(23)->ELinkPos != 3))
13500  {
13501  LeadingPointsAtLastElement = true;
13502  Utilities->CallLogPop(1492);
13503  return;
13504  }
13505  for(unsigned int x = 0; x < PrefDirSize(); x++)
13506  {
13507  TPrefDirElement PrefDirElement = GetFixedPrefDirElementAt(166, x);
13508  if((PrefDirElement.GetELinkPos() > 1) || (PrefDirElement.GetXLinkPos() > 1)) // 'or' because points may have one == 0 & other == 3
13509  {
13510  OverallDistance += PrefDirElement.Length23;
13511  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13512  {
13513  if(x == 0)
13514  {
13515  OverallSpeedLimit = PrefDirElement.SpeedLimit23;
13516  }
13517  else
13518  {
13519  if(OverallSpeedLimit != PrefDirElement.SpeedLimit23)
13520  {
13521  OverallSpeedLimit = -1;
13522  }
13523  }
13524  }
13525  }
13526  else
13527  {
13528  OverallDistance += PrefDirElement.Length01;
13529  if(OverallSpeedLimit != -1) // if set to -1 there are mixed speed limits
13530  {
13531  if(x == 0)
13532  {
13533  OverallSpeedLimit = PrefDirElement.SpeedLimit01;
13534  }
13535  else
13536  {
13537  if(OverallSpeedLimit != PrefDirElement.SpeedLimit01)
13538  {
13539  OverallSpeedLimit = -1;
13540  }
13541  }
13542  }
13543  }
13544  }
13545  Utilities->CallLogPop(1529);
13546 }
13547 
13548 // ---------------------------------------------------------------------------
13549 
13550 void TOnePrefDir::WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
13551 {
13552  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WritePrefDirToImage");
13553  if(PrefDirSize() == 0)
13554  {
13555  Utilities->CallLogPop(1564);
13556  return;
13557  }
13558  int H, V, HLoc, VLoc, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13559  bool FoundFlag;
13561  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13562 
13563  while(MMIT != PrefDir4MultiMap.end())
13564  {
13565  HLoc = MMIT->first.first;
13566  VLoc = MMIT->first.second;
13567  GetVectorPositionsFromPrefDir4MultiMap(7, HLoc, VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13568  H = HLoc - Track->GetHLocMin();
13569  V = VLoc - Track->GetVLocMin();
13570  // always found in order, any missing have PrefDirPosx == -1
13571  if(PrefDirPos0 > -1)
13572  {
13573  PrefDirElement0 = GetFixedPrefDirElementAt(174, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13574  }
13575  if(PrefDirPos1 > -1)
13576  {
13577  PrefDirElement1 = GetFixedPrefDirElementAt(175, PrefDirPos1);
13578  }
13579  if(PrefDirPos2 > -1)
13580  {
13581  PrefDirElement2 = GetFixedPrefDirElementAt(176, PrefDirPos2);
13582  }
13583  if(PrefDirPos3 > -1)
13584  {
13585  PrefDirElement3 = GetFixedPrefDirElementAt(177, PrefDirPos3);
13586  }
13587  if(PrefDirPos3 > -1) // 4 found, mark all PrefDirs bidirectional (operator == ensures no duplicates in ConsolidatePrefDirs)
13588  {
13589  // need to plot all 4 in order to obtain all the direction graphics
13590  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13591  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13592  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13593  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13594  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13595  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13596  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetRouteGraphicPtr(false, true)); // green
13597  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement3.GetDirectionRouteGraphicPtr(false, true)); // green
13598  MMIT++;
13599  MMIT++;
13600  MMIT++;
13601  MMIT++;
13602  }
13603  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13604  {
13605  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13606  {
13607  // 0 & 1 constitute the bidirectional PrefDir
13608  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13609  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13610  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13611  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13612  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, false)); // red
13613  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, false)); // red
13614  MMIT++;
13615  MMIT++;
13616  MMIT++;
13617  }
13618  else if(PrefDirElement0.EXNumber == PrefDirElement2.EXNumber)
13619  {
13620  // 0 & 2 constitute the bidirectional PrefDir
13621  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13622  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13623  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13624  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13625  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13626  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13627  MMIT++;
13628  MMIT++;
13629  MMIT++;
13630  }
13631  else
13632  {
13633  // 1 & 2 constitute the bidirectional PrefDir
13634  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13635  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13636  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetRouteGraphicPtr(false, true)); // green
13637  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement2.GetDirectionRouteGraphicPtr(false, true)); // green
13638  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13639  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13640  MMIT++;
13641  MMIT++;
13642  MMIT++;
13643  }
13644  }
13645  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13646  {
13647  if(PrefDirElement0.EXNumber == PrefDirElement1.EXNumber)
13648  {
13649  // 0 & 1 constitute the bidirectional PrefDir
13650  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, true)); // green
13651  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, true)); // green
13652  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, true)); // green
13653  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, true)); // green
13654  MMIT++;
13655  MMIT++;
13656  }
13657  else
13658  {
13659  // 2 unidirectional PrefDirs
13660  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13661  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13662  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetRouteGraphicPtr(false, false)); // red
13663  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement1.GetDirectionRouteGraphicPtr(false, false)); // red
13664  MMIT++;
13665  MMIT++;
13666  }
13667  }
13668  else if(PrefDirPos0 > -1) // 1 found, must be unidirectional
13669  {
13670  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetRouteGraphicPtr(false, false)); // red
13671  Bitmap->Canvas->Draw((H * 16), (V * 16), PrefDirElement0.GetDirectionRouteGraphicPtr(false, false)); // red
13672  MMIT++;
13673  }
13674  }
13675  Utilities->CallLogPop(1565);
13676 }
13677 
13678 // ---------------------------------------------------------------------------
13679 
13680 bool TOnePrefDir::PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos) // added at v1.2.0
13681 /*
13682  Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entry position, not points, crossovers,
13683  level crossing, signals with wrong direction set, or buffers.
13684 */
13685 {
13686  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteElementValid");
13687  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13688  bool FoundFlag;
13690  TPrefDirElement PrefDirElement0, PrefDirElement1, PrefDirElement2, PrefDirElement3;
13691 
13692  if((ElementIn.TrackType == Points) || (ElementIn.TrackType == Crossover) || (ElementIn.TrackType == Buffers) || (Track->IsLCAtHV(49, ElementIn.HLoc,
13693  ElementIn.VLoc)))
13694  {
13695  Utilities->CallLogPop(1982);
13696  return(false);
13697  }
13698  if((ElementIn.TrackType == SignalPost) && (ElementIn.Config[EntryPos] == Signal)) // Signal is at exit end
13699  {
13700  Utilities->CallLogPop(1983);
13701  return(false);
13702  }
13703  if((ElementIn.TrackType == SignalPost) && (ElementIn.SigAspect == TTrackElement::GroundSignal))
13704  {
13705  Utilities->CallLogPop(1995);
13706  return(false);
13707  }
13708 // Now check that there is only a single prefdir set
13709  GetVectorPositionsFromPrefDir4MultiMap(8, ElementIn.HLoc, ElementIn.VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13710 // always found in order, any missing have PrefDirPosx == -1
13711  if(PrefDirPos0 > -1)
13712  {
13713  PrefDirElement0 = GetFixedPrefDirElementAt(213, PrefDirPos0); // PrefDirPos0 should always be > -1 but leave as a precaution
13714  }
13715  if(PrefDirPos1 > -1)
13716  {
13717  PrefDirElement1 = GetFixedPrefDirElementAt(214, PrefDirPos1);
13718  }
13719  if(PrefDirPos2 > -1)
13720  {
13721  PrefDirElement2 = GetFixedPrefDirElementAt(215, PrefDirPos2);
13722  }
13723  if(PrefDirPos3 > -1)
13724  {
13725  PrefDirElement3 = GetFixedPrefDirElementAt(216, PrefDirPos3);
13726  }
13727  if(PrefDirPos3 > -1) // 4 found, all bidirectional
13728  {
13729  Utilities->CallLogPop(1984);
13730  return(false);
13731  }
13732  else if(PrefDirPos2 > -1) // 3 found, one PrefDir bidirectional & other unidirectional
13733  {
13734  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos) || (PrefDirElement2.XLinkPos == EntryPos))
13735  {
13736  Utilities->CallLogPop(1985);
13737  return(false);
13738  }
13739  else
13740  {
13741  Utilities->CallLogPop(1986);
13742  return(true);
13743  }
13744  }
13745  else if(PrefDirPos1 > -1) // 2 found, either 1 bidirectional or 2 unidirectional
13746  {
13747  if((PrefDirElement0.XLinkPos == EntryPos) || (PrefDirElement1.XLinkPos == EntryPos))
13748  {
13749  Utilities->CallLogPop(1987);
13750  return(false);
13751  }
13752  else
13753  {
13754  Utilities->CallLogPop(1988);
13755  return(true);
13756  }
13757  }
13758  else if(PrefDirPos0 > -1) // one found, make sure in correct direction
13759  {
13760  if(PrefDirElement0.XLinkPos == EntryPos)
13761  {
13762  Utilities->CallLogPop(1989);
13763  return(false);
13764  }
13765  else
13766  {
13767  Utilities->CallLogPop(1990);
13768  return(true);
13769  }
13770  }
13771  else
13772  {
13773  Utilities->CallLogPop(1991);
13774  return(false); // none found
13775  }
13776 }
13777 
13778 // ---------------------------------------------------------------------------
13779 
13781 {
13782 /* //Added at v2.1.0
13783  Called by GetStartAndEndPrefDirElements, which in turn is called by PresetAutoSigRoutesButtonClick. Checks for a diagonal link in
13784  the autosigsroute being fouled by an adjacent track with a corresponding link that meets at the diagonal link, and if it is it
13785  returns true and prevents the route being set. Note that adjacent track consisting of buffers, gaps and continuations at the
13786  diagonal link are also excluded though they need not be, but it makes the check code simpler and such adjacent track is untidy
13787  and can be modelled better anyway.
13788 
13789  Enter with PrefDirElement whose XLink is to be checked for track that fouls a diagonal.
13790  If XLink is anything but 1,3,7 or 9 return false - no fouling as not a diagonal.
13791  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13792  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13793  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13794  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13795 */
13796  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PresetAutoRouteDiagonalFouledByTrack," + ElementIn.HLoc + "," +
13797  ElementIn.VLoc + "," + XLink);
13798  int TrackVecPos;
13799  bool TrackFoundFlag;
13800  TTrackElement TempTrackElement;
13801 
13802  if((XLink == 2) || (XLink == 4) || (XLink == 6) || (XLink == 8))
13803  {
13804  Utilities->CallLogPop(2047);
13805  return(false);
13806  }
13807 // for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
13808  if(XLink == 1)
13809  {
13810  TrackVecPos = Track->GetVectorPositionFromTrackMap(48, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13811  if(TrackFoundFlag)
13812  {
13813  TempTrackElement = Track->TrackElementAt(898, TrackVecPos);
13814  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13815  {
13816  Utilities->CallLogPop(2048);
13817  return(true);
13818  }
13819  }
13820  TrackVecPos = Track->GetVectorPositionFromTrackMap(49, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13821  if(TrackFoundFlag)
13822  {
13823  TempTrackElement = Track->TrackElementAt(899, TrackVecPos);
13824  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13825  {
13826  Utilities->CallLogPop(2049);
13827  return(true);
13828  }
13829  }
13830  }
13831 // for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
13832  if(XLink == 3)
13833  {
13834  TrackVecPos = Track->GetVectorPositionFromTrackMap(50, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13835  if(TrackFoundFlag)
13836  {
13837  TempTrackElement = Track->TrackElementAt(900, TrackVecPos);
13838  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13839  {
13840  Utilities->CallLogPop(2050);
13841  return(true);
13842  }
13843  }
13844  TrackVecPos = Track->GetVectorPositionFromTrackMap(51, ElementIn.HLoc, ElementIn.VLoc - 1, TrackFoundFlag);
13845  if(TrackFoundFlag)
13846  {
13847  TempTrackElement = Track->TrackElementAt(901, TrackVecPos);
13848  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13849  {
13850  Utilities->CallLogPop(2051);
13851  return(true);
13852  }
13853  }
13854  }
13855 // for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
13856  if(XLink == 7)
13857  {
13858  TrackVecPos = Track->GetVectorPositionFromTrackMap(52, ElementIn.HLoc - 1, ElementIn.VLoc, TrackFoundFlag);
13859  if(TrackFoundFlag)
13860  {
13861  TempTrackElement = Track->TrackElementAt(902, TrackVecPos);
13862  if((TempTrackElement.Link[0] == 9) || (TempTrackElement.Link[1] == 9) || (TempTrackElement.Link[2] == 9) || (TempTrackElement.Link[3] == 9))
13863  {
13864  Utilities->CallLogPop(2052);
13865  return(true);
13866  }
13867  }
13868  TrackVecPos = Track->GetVectorPositionFromTrackMap(53, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13869  if(TrackFoundFlag)
13870  {
13871  TempTrackElement = Track->TrackElementAt(903, TrackVecPos);
13872  if((TempTrackElement.Link[0] == 1) || (TempTrackElement.Link[1] == 1) || (TempTrackElement.Link[2] == 1) || (TempTrackElement.Link[3] == 1))
13873  {
13874  Utilities->CallLogPop(2053);
13875  return(true);
13876  }
13877  }
13878  }
13879 // for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
13880  if(XLink == 9)
13881  {
13882  TrackVecPos = Track->GetVectorPositionFromTrackMap(54, ElementIn.HLoc + 1, ElementIn.VLoc, TrackFoundFlag);
13883  if(TrackFoundFlag)
13884  {
13885  TempTrackElement = Track->TrackElementAt(904, TrackVecPos);
13886  if((TempTrackElement.Link[0] == 7) || (TempTrackElement.Link[1] == 7) || (TempTrackElement.Link[2] == 7) || (TempTrackElement.Link[3] == 7))
13887  {
13888  Utilities->CallLogPop(2054);
13889  return(true);
13890  }
13891  }
13892  TrackVecPos = Track->GetVectorPositionFromTrackMap(55, ElementIn.HLoc, ElementIn.VLoc + 1, TrackFoundFlag);
13893  if(TrackFoundFlag)
13894  {
13895  TempTrackElement = Track->TrackElementAt(905, TrackVecPos);
13896  if((TempTrackElement.Link[0] == 3) || (TempTrackElement.Link[1] == 3) || (TempTrackElement.Link[2] == 3) || (TempTrackElement.Link[3] == 3))
13897  {
13898  Utilities->CallLogPop(2055);
13899  return(true);
13900  }
13901  }
13902  }
13903  Utilities->CallLogPop(2056);
13904  return(false);
13905 }
13906 
13907 // ---------------------------------------------------------------------------
13908 
13909 bool TOnePrefDir::GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
13910 {
13911 /* Called by PresetAutoSigRoutesButtonClick in the Interface unit. LastIteratorValue gives the position in EveryPrefDir to start from. Search
13912  EveryPrefDir for continuations (facing inwards wrt pref dir) or non-ground signals in single direction pref dirs, and when find one track forwards
13913  to the next non-ground signal or continuation. If, before finding a valid signal or continuation find points, crossover, level crossing or buffers,
13914  or an element that is already in a route, stop tracking and continue with the search for another valid continuation or signal. When find a suitable
13915  pair, return the elements in StartElement and EndElement, and also the LastIteratorValue ready for the next call.
13916 */
13917  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetStartAndEndPrefDirElements," + AnsiString(LastIteratorValue));
13919  bool FoundFlag, ContFlag, FoundElements = false;
13920  int PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3;
13921  TPrefDirElement NextElement;
13922 
13923  for(PDVIt = (PrefDirVector.begin() + LastIteratorValue); PDVIt < PrefDirVector.end(); PDVIt++)
13924  {
13925  LastIteratorValue++;
13926  ContFlag = false;
13927  if((PDVIt->TrackType != SignalPost) && (PDVIt->TrackType != Continuation))
13928  {
13929  continue;
13930  }
13931  if((PDVIt->TrackType == SignalPost) && (PDVIt->SigAspect == TTrackElement::GroundSignal))
13932  {
13933  continue;
13934  }
13935 // if(AllRoutes::TrackIsInARoute(, PDVIt->TrackVectorPosition, PDVIt->EntryPos) continue; //already in a route - no, don't check start position as if a signal might well be at end of an existing route
13936  // found a potential route start point
13937  if(PresetAutoRouteDiagonalFouledByTrack(0, *PDVIt, PDVIt->XLink)) // Added at v2.1.0
13938  {
13939  continue;
13940  }
13941  if(PresetAutoRouteElementValid(0, *PDVIt, PDVIt->ELinkPos))
13942  {
13943  // check if continuation either in a route or with prefdir facing 'End' (OK if find it as EndElement, but not as StartElement)
13944  if(PDVIt->TrackType == Continuation)
13945  {
13946  if(AllRoutes->TrackIsInARoute(18, PDVIt->TrackVectorPosition, PDVIt->ELinkPos))
13947  {
13948  continue;
13949  }
13950  if(PDVIt->XLinkPos == 0) // position 0 is the continuation
13951  {
13952  continue;
13953  }
13954  }
13955  StartElement = *PDVIt;
13956 // in Glenn Mitchell's error log (14/04/13) the offending signal start position was 4680, problem was it linked to a point with pref dirs set on through track but signal linked to
13957  // diverging track on which there was no pref dir. See below for 2 required changes.
13958  }
13959  else
13960  {
13961  continue;
13962  }
13963  // now track along until find a signal or continuation, checking validity for each element
13964  int NextTrackVectorPosition = PDVIt->Conn[PDVIt->GetXLinkPos()];
13965  GetVectorPositionsFromPrefDir4MultiMap(9, Track->TrackElementAt(878, NextTrackVectorPosition).HLoc,
13966  Track->TrackElementAt(879, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
13967  if(PrefDirPos0 == -1) // no continuing prefdir
13968  {
13969  continue;
13970  }
13971  bool NextElementFoundFlag = false;
13972  if(GetFixedPrefDirElementAt(217, PrefDirPos0).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13973  {
13974  NextElement = GetFixedPrefDirElementAt(218, PrefDirPos0);
13975  NextElementFoundFlag = true;
13976  }
13977  if(PrefDirPos1 > -1)
13978  {
13979  if(GetFixedPrefDirElementAt(219, PrefDirPos1).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13980  {
13981  NextElement = GetFixedPrefDirElementAt(220, PrefDirPos1);
13982  NextElementFoundFlag = true;
13983  }
13984  }
13985  if(PrefDirPos2 > -1)
13986  {
13987  if(GetFixedPrefDirElementAt(221, PrefDirPos2).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13988  {
13989  NextElement = GetFixedPrefDirElementAt(222, PrefDirPos2);
13990  NextElementFoundFlag = true;
13991  }
13992  }
13993  if(PrefDirPos3 > -1)
13994  {
13995  if(GetFixedPrefDirElementAt(223, PrefDirPos3).ELinkPos == PDVIt->ConnLinkPos[PDVIt->GetXLinkPos()])
13996  {
13997  NextElement = GetFixedPrefDirElementAt(224, PrefDirPos3);
13998  NextElementFoundFlag = true;
13999  }
14000  }
14001  if(!NextElementFoundFlag)
14002  {
14003  continue; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14004 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (1)")); //[GM error 14/04/13] for next release change this to 'continue;' to quit from trying to find the auto route (don't need to throw an exception)
14005  }
14006  while(true)
14007  {
14008  // check validity
14009  if(PresetAutoRouteDiagonalFouledByTrack(1, NextElement, NextElement.XLink)) // Added at v2.1.0
14010  {
14011  ContFlag = true;
14012  break;
14013  }
14014  if(!PresetAutoRouteElementValid(1, NextElement, NextElement.ELinkPos))
14015  {
14016  ContFlag = true;
14017  break;
14018  }
14019  // check if in a route, providing not a signal, as a signal might be at the start of a route
14020  if(NextElement.TrackType != SignalPost)
14021  {
14022  if(AllRoutes->TrackIsInARoute(17, NextElement.TrackVectorPosition, NextElement.ELinkPos))
14023  {
14024  ContFlag = true;
14025  break;
14026  }
14027  }
14028  if((NextElement.TrackType == SignalPost) || (NextElement.TrackType == Continuation))
14029  // can't be a gound signal as would have failed the validity test
14030  {
14031  EndElement = NextElement;
14032  break;
14033  }
14034  // get the next element in the sequence
14035  NextTrackVectorPosition = NextElement.Conn[NextElement.GetXLinkPos()];
14036  GetVectorPositionsFromPrefDir4MultiMap(10, Track->TrackElementAt(880, NextTrackVectorPosition).HLoc,
14037  Track->TrackElementAt(881, NextTrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14038  if(PrefDirPos0 == -1) // no continuing prefdir
14039  {
14040  ContFlag = true;
14041  break;
14042  }
14043  if(GetFixedPrefDirElementAt(225, PrefDirPos0).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14044  {
14045  NextElement = GetFixedPrefDirElementAt(226, PrefDirPos0);
14046  continue;
14047  }
14048  if(PrefDirPos1 > -1)
14049  {
14050  if(GetFixedPrefDirElementAt(227, PrefDirPos1).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14051  {
14052  NextElement = GetFixedPrefDirElementAt(228, PrefDirPos1);
14053  continue;
14054  }
14055  }
14056  if(PrefDirPos2 > -1)
14057  {
14058  if(GetFixedPrefDirElementAt(229, PrefDirPos2).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14059  {
14060  NextElement = GetFixedPrefDirElementAt(230, PrefDirPos2);
14061  continue;
14062  }
14063  }
14064  if(PrefDirPos3 > -1)
14065  {
14066  if(GetFixedPrefDirElementAt(231, PrefDirPos3).ELinkPos == NextElement.ConnLinkPos[NextElement.GetXLinkPos()])
14067  {
14068  NextElement = GetFixedPrefDirElementAt(232, PrefDirPos3);
14069  continue;
14070  }
14071  }
14072  // had exception thrown here if NextElement not found, but could be a bridge where opposite track PrefDir set, in which case won't find it
14073  // found with Jonathan Kwok's DLR railway (17/11/12) where undertrack PrefDir not set just west of Poplar. Hence first test if element is a bridge
14074  // and if so set ContFlag to true & break (same as not finding PrefDir element at all). Modified at version 1.3.1
14075  // note that it's not NextElement that is to be examined but NextTrackVectorPosition, which can be found easily by using PrefDirPos0 (there will be a
14076  // PrefDirPos0 or would have exited earlier, and it doesn't matter that PrefDirPos0 isn't on the route in question because only the TrackType is needed)
14077  if(GetFixedPrefDirElementAt(243, PrefDirPos0).TrackType == Bridge)
14078  {
14079  ContFlag = true;
14080  break;
14081  }
14082  else
14083  {
14084  ContFlag = true; // Modified for release 1.3.2 (sent as beta to John Phillipson initially)
14085  // could drop the bridge test but keep it to show the change history
14086  break;
14087 // throw(Exception("Failed to track prefdir in PresetAutoSigRoutesButtonClick (2)")); //[GM error 14/04/13] for next release set ContFlag to true & break' to quit from trying to find the auto route (don't need to throw an exception)
14088  }
14089  }
14090  if(ContFlag)
14091  {
14092  continue;
14093  }
14094  // else have start and end elements set & all elements valid, so set up the route segment
14095  FoundElements = true;
14096  break;
14097  }
14098  if(FoundElements)
14099  {
14100  Utilities->CallLogPop(1992);
14101  return(true);
14102  }
14103  else
14104  {
14105  Utilities->CallLogPop(1993);
14106  return(false);
14107  }
14108 }
14109 
14110 // ---------------------------------------------------------------------------
14111 // TOneRoute
14112 // ---------------------------------------------------------------------------
14113 
14114 bool TOneRoute::GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
14115 {
14116 /* General:
14117  The basis of all these route setting functions, preferred and non-preferred, is that a SearchVector is set up
14118  containing all the new elements to form the route. When complete, the SearchVector is converted into route
14119  elements, either as a new route, or an extension to an existing route. The AutoSigs flag determines whether the
14120  route will use automatic signals or not.
14121  For preferred and non-preferred routes, all new elements (as opposed to those already in existing routes) go
14122  into the SearchVector. For non-preferred routes, trackelements are selected that are not necessarily PrefDir
14123  elements, so additional work is needed to complete all their members before they are ready for conversion into
14124  a route - see SetRemainingSearchVectorValues. The call order is GetStart....; GetNext...,
14125  which includes the Search... function; [SetRemainingSearchVectorValues for non-preferred routes only], then
14126  ConvertAndAdd.......
14127 */
14128  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetPreferredRouteStartElement," + AnsiString(HLoc) + "," +
14129  AnsiString(VLoc) + "," + AnsiString((short)AutoSigsFlag));
14130  ClearRoute();
14131  int TrackVectorPosition;
14132  TTrackElement TrackElement;
14133  TPrefDirElement FirstElement, LastElement;
14134 
14135  if(!(Track->FindNonPlatformMatch(7, HLoc, VLoc, TrackVectorPosition, TrackElement)))
14136  {
14137  Utilities->CallLogPop(199);
14138  return(false);
14139  }
14140  if(AutoSigsFlag && (TrackElement.TrackType == Buffers)) // added at v1.2.0
14141  {
14142  TrainController->StopTTClockMessage(80, "Can't create an automatic signal route from buffers");
14143  Utilities->CallLogPop(1996);
14144  return(false);
14145  }
14146  else if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14147  {
14148  TrainController->StopTTClockMessage(7, "Must select a valid signal, buffers or continuation");
14149  Utilities->CallLogPop(200);
14150  return(false);
14151  }
14152  if(Track->IsLCAtHV(18, HLoc, VLoc))
14153  {
14154  TrainController->StopTTClockMessage(73, "Can't start a route on a level crossing");
14155  Utilities->CallLogPop(1909);
14156  return(false);
14157  }
14158 // check if selected a train & disallow if so
14159  if(TrackElement.TrainIDOnElement > -1)
14160  {
14161  TrainController->StopTTClockMessage(9, "Can't start a route on a train");
14162  Utilities->CallLogPop(202);
14163  return(false);
14164  }
14165 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
14166  TPrefDirElement PrefDirElement;
14167  int LockedVectorNumber;
14168 
14169  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(1, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
14170  {
14171  TrainController->StopTTClockMessage(10, "Can't start a route on a locked route");
14172  Utilities->CallLogPop(203);
14173  return(false);
14174  }
14175  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(2, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
14176  {
14177  TrainController->StopTTClockMessage(11, "Can't start a route on a locked route");
14178  Utilities->CallLogPop(204);
14179  return(false);
14180  }
14182  StartRoutePosition = TrackVectorPosition; // actual route start - may be element following StartRouteSelectPosition if select a
14183 // signal in an autosig route & follow with a non-autosig route
14184 
14185  TPrefDirElement BlankElement;
14186 
14187  StartElement1 = BlankElement;
14188  StartElement2 = BlankElement; //not used in this routine but used in GetNextPreferred.... though could probably dispense with it there
14189 // check it's in a PrefDir (could be 2 entries for two possible PrefDirs, can only select single track elements so can't have more than 2 PrefDirs)
14190  bool InPrefDirFlag = false;
14191 
14192  bool FoundFlag;
14193  int PrefDirPos0 = -1;
14194  int PrefDirPos1 = -1;
14195  int PrefDirPos2 = -1;
14196  int PrefDirPos3 = -1;
14197 
14199  Track->TrackElementAt(85, StartRoutePosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14200  int PrefDirVecPos[4] =
14201  {
14202  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14203  };
14204 
14205  for(int x = 0; x < 4; x++)
14206  {
14207  int b = PrefDirVecPos[x];
14208  if(b > -1)
14209  {
14210  // only allow the appropriate exit route to be searched
14211  if(((TrackElement.TrackType == SignalPost) && (EveryPrefDir->GetFixedPrefDirElementAt(15, b).Config[EveryPrefDir->GetFixedPrefDirElementAt(16,
14212  b).XLinkPos] == Signal)) || ((TrackElement.TrackType == Buffers) && (EveryPrefDir->GetFixedPrefDirElementAt(17,
14213  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(18, b).XLinkPos] == Connection)) ||
14214  ((TrackElement.TrackType == Continuation) && (EveryPrefDir->GetFixedPrefDirElementAt(19,
14215  b).Config[EveryPrefDir->GetFixedPrefDirElementAt(20, b).XLinkPos] == Connection)))
14216  {
14217  InPrefDirFlag = true;
14218  StartElement1 = EveryPrefDir->GetFixedPrefDirElementAt(21, b);
14219  if(AutoSigsFlag)
14220  {
14221  StartElement1.AutoSignals = true;
14222  }
14223  StartElement1.PrefDirRoute = true;
14224  }
14225  }
14226  }
14227 
14228  if(!InPrefDirFlag)
14229  {
14231  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14232  Utilities->CallLogPop(205);
14233  return(false);
14234  }
14235 // look for exact match in a route first - can't be a bridge so can use a simple 'find'
14237  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(14, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14238 
14239  if(DummyPair.first > -1) // if DummyPair exists then an error as start element can only be in one route (bridges not allowed)
14240  {
14241  throw Exception("Selection in two routes - should never happen!");
14242  }
14243  if(RoutePair.first > -1) // no need to examine DummyPair as start element can only be in one route (bridges not allowed)
14244  {
14245  if(RoutePair.second != AllRoutes->GetFixedRouteAt(1, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
14246  {
14247  TrainController->StopTTClockMessage(13, "Can't start a route within or at the start of an existing route");
14248  Utilities->CallLogPop(206);
14249  return(false);
14250  }
14251  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(2, RoutePair.first).GetFixedPrefDirElementAt(29, RoutePair.second);
14252  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
14253  {
14254  TrainController->StopTTClockMessage(14, "No forward connection from this position");
14255  Utilities->CallLogPop(207);
14256  return(false);
14257  }
14258  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(9, RouteElement.Conn[RouteElement.XLinkPos],
14259  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
14260  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14261  {
14262  TrainController->StopTTClockMessage(15, "Can't start a route at an element that links forward into an existing route");
14263  Utilities->CallLogPop(208);
14264  return(false);
14265  }
14266  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(158, RoutePair.first).RouteID);
14268  AllRoutes->GetFixedRouteAt(4, RoutePair.first).PrefDirSize() - 1); // last element
14269  if(AutoSigsFlag)
14270  {
14271  StartElement1.AutoSignals = true;
14272  }
14273  StartElement1.PrefDirRoute = true;
14275  Utilities->CallLogPop(209);
14276  return(true); // all retained values (StartElement1 & maybe 2; StartRoutePosition) set
14277  }
14278 
14279  else // no route started
14280  {
14281 // check if selected position is adjacent to start or end of an existing route and disallow
14282  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14283  {
14284  FirstElement = AllRoutes->GetFixedRouteAt(5, a).GetFixedPrefDirElementAt(31, 0);
14285  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
14286  {
14287  TrainController->StopTTClockMessage(16, "Can't make selection adjacent to start of another route");
14288  Utilities->CallLogPop(210);
14289  return(false);
14290  }
14291  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
14292  {
14293  TrainController->StopTTClockMessage(17, "Can't make selection adjacent to start of another route");
14294  Utilities->CallLogPop(211);
14295  return(false);
14296  }
14297  }
14298 
14299 // check if it's adjacent to end of an an existing route,
14300  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14301  {
14303  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
14304  {
14305  TrainController->StopTTClockMessage(18, "Can't start a route adjacent to the end of an existing route");
14306  Utilities->CallLogPop(212);
14307  return(false);
14308  }
14309  }
14310  SearchVector.push_back(StartElement1);
14311  Utilities->CallLogPop(213);
14312  return(true);
14313  }
14314 }
14315 
14316 // ---------------------------------------------------------------------------
14317 
14318 bool TOneRoute::GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag,
14319  IDInt &ReqPosRouteID, bool &PointsChanged)
14320 
14321 /*
14322  Return true if select valid next element, in which case the route is set & stored in SearchVector. Return false for an invalid next element.
14323 
14324  Declare integers EndPosition (the position used) and ReqPosRouteID to hold (when required) the existing route selected (for linking to an existing route),
14325  this being set to -1 for not used.
14326  Check if selection is a valid track element, cancel if not, if select original start element or if select buffers
14327  with AutoSigsFlag set - would have no way out and no way to cancel the route with a train at the buffers.
14328  Check correct type of element - signal/buffers/continuation.
14329  Fail if train on element, or if selection not in EveryPrefDir. Otherwise set EndElement1 & possibly also
14330  EndElement2 corresponding to the 2 possible PrefDir elements).
14331  Check if selection is first element in an existing route & if so set ReqPosRouteID, EndElement1, and set EndElement2 to
14332  blank as can only be one route at that element (can't select bridges). Fail if in a route & not at start, or at start but route
14333  linked forward to another route.
14334  Check & fail if adjacent to start or end of an existing route, or if select the route that selected at start (though earlier check
14335  for same position as start should cover this)
14336 
14337  If there's a StartSelectionRouteID then StartElement1 will be set to the last entry in the selected route so use
14338  SearchForPreferredRoute to search for the selected end element from this start element. If succeed then set the search vector
14339  graphics using SetRouteSearchVectorGraphics(AutoSigsFlag) & return true, for Interface to handle the flashing & time delay. After the
14340  delay completes the Interface flasher calls ConvertAndAddPreferredRouteSearchVector to add the new route to the AllRoutesVectorPtr.
14341  If the search fails then return false.
14342  If there isn't a StartSelectionRouteID then the starting element is not already in a route, so it will have been stored
14343  in the SearchVector to ensure it's entered as part of the new route.
14344  First check whether the selected element (either EndElement1 or 2) is adjacent to the starting position and if so set the route to go
14345  directly to it (as opposed to going round a long loop to get to it just because that XLinkPos happens to be chosen first. If not
14346  adjacent then first search on EndElement1, and if fail search on EndElement2 providing it's set. If succeed
14347  set the search vector graphics as above and return. If reach end of function then have failed to find a valid element,
14348  so return false, with an appropriate message if ConsecSignalsRoute set.
14349 */
14350 
14351 {
14352  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextPreferredRouteElement," + AnsiString(HLoc) + "," +
14353  AnsiString(VLoc) + "," + AnsiString((short)ConsecSignals) + "," + AnsiString((short)AutoSigsFlag));
14354  int EndPosition; // the position selected
14355 
14356  Track->LCFoundInAutoSigsRoute = false;
14358  TotalSearchCount = 0;
14359  ReqPosRouteID = IDInt(-1); // default value for not used
14360  TTrackElement TrackElement;
14361  TPrefDirElement EndElement1, EndElement2, BlankElement; // all blank to begin with, can only have max of 2 PrefDirs on a
14362  // given element as can't select 2-track elements
14363  if(!(Track->FindNonPlatformMatch(8, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
14364  {
14365  Utilities->CallLogPop(214);
14366  return(false);
14367  }
14368  if(Track->IsLCAtHV(19, HLoc, VLoc))
14369  {
14370  TrainController->StopTTClockMessage(72, "Can't end a route on a level crossing");
14371  Utilities->CallLogPop(1908);
14372  return(false);
14373  }
14374 // cancel selection if on original start element
14375  if(EndPosition == StartRoutePosition)
14376  {
14377  Utilities->CallLogPop(215);
14378  return(false);
14379  }
14380  if(AutoSigsFlag)
14381  {
14382  if(TrackElement.TrackType == Buffers)
14383  {
14384  TrainController->StopTTClockMessage(19, "Can't create an automatic signal route into buffers");
14385  Utilities->CallLogPop(216);
14386  return(false);
14387  }
14388  }
14389  if((TrackElement.TrackType != SignalPost) && (TrackElement.TrackType != Buffers) && (TrackElement.TrackType != Continuation))
14390  {
14391  TrainController->StopTTClockMessage(20, "Must select a valid signal, buffers or continuation");
14392  Utilities->CallLogPop(217);
14393  return(false);
14394  }
14395 // check if train on element
14396  if(TrackElement.TrainIDOnElement > -1)
14397  {
14398  TrainController->StopTTClockMessage(22, "Can't end a route on a train");
14399  Utilities->CallLogPop(219);
14400  return(false);
14401  }
14402 // disallow if not in EveryPrefDir & set EndElement(s)
14403  bool InPrefDirFlag = false;
14404 
14405  bool FoundFlag;
14406  int PrefDirPos0 = -1;
14407  int PrefDirPos1 = -1;
14408  int PrefDirPos2 = -1;
14409  int PrefDirPos3 = -1;
14410 
14411  EveryPrefDir->GetVectorPositionsFromPrefDir4MultiMap(4, Track->TrackElementAt(86, EndPosition).HLoc, Track->TrackElementAt(87, EndPosition).VLoc, FoundFlag,
14412  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
14413  int PrefDirVecPos[4] =
14414  {
14415  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
14416  };
14417 
14418  for(int x = 0; x < 4; x++)
14419  {
14420  int b = PrefDirVecPos[x];
14421  if(b > -1)
14422  {
14423  InPrefDirFlag = true;
14424  if(EndElement1.TrackVectorPosition == -1)
14425  {
14426  EndElement1 = EveryPrefDir->GetFixedPrefDirElementAt(33, b);
14427  }
14428  else
14429  {
14430  EndElement2 = EveryPrefDir->GetFixedPrefDirElementAt(34, b);
14431  }
14432  }
14433  }
14434  if(!InPrefDirFlag)
14435  {
14437  "Route and preferred direction mismatch. If no preferred direction then only red routes can be used. Green and blue route directions must correspond to the preferred direction.");
14438  Utilities->CallLogPop(220);
14439  return(false);
14440  }
14441 // check if in an existing route - can't be a bridge so can use a simple 'find'
14442 // bool InRoute = false;
14444  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(15, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
14445 
14446  if(RoutePair.first > -1)
14447  {
14448  if(RoutePair.second != 0) // not first element in existing route so no good
14449  {
14450  TrainController->StopTTClockMessage(24, "Can't end a route within or at the end of an existing route");
14451  Utilities->CallLogPop(221);
14452  return(false);
14453  }
14454  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(8, RoutePair.first).GetFixedPrefDirElementAt(35, RoutePair.second);
14455 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
14456  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(10, RouteElement.Conn[RouteElement.ELinkPos],
14457  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
14458  // discovered when timetable building for Joshua Coupe's railway. Also affects non-preferred routes - see below
14459  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
14460  {
14461  TrainController->StopTTClockMessage(25, "Can't start a route within or at the end of an existing route");
14462  Utilities->CallLogPop(222);
14463  return(false);
14464  }
14465  EndElement1 = RouteElement;
14466  EndElement2 = BlankElement; // only need the route element
14467  EndPosition = EndElement1.TrackVectorPosition;
14468  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(160, RoutePair.first).RouteID);
14469  }
14470 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
14471 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
14472 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
14473 
14474  if(EndElement1.HLoc >= StartElement1.HLoc)
14475  {
14477  SearchLimitHighH = EndElement1.HLoc + 15;
14478  }
14479  else
14480  {
14481  SearchLimitLowH = EndElement1.HLoc - 15;
14483  }
14484  if(EndElement1.VLoc >= StartElement1.VLoc)
14485  {
14487  SearchLimitHighV = EndElement1.VLoc + 15;
14488  }
14489  else
14490  {
14491  SearchLimitLowV = EndElement1.VLoc - 15;
14493  }
14494 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
14495  check & TotalSearchCounts check
14496  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
14497  {
14498  TrainController->StopTTClockMessage(65, "Unable to reach the selected element - too far ahead");
14499  Utilities->CallLogPop(1693);
14500  return false;
14501  }
14502 */
14503 // check if adjacent to start and disallow
14504  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
14505  {
14507  int AdjLinkPos = AllRoutes->GetFixedRouteAt(218, a).GetFixedPrefDirElementAt(244, 0).ELinkPos; // added at v1.3.1
14508 // if((EndElement1.Config[EndElement1.XLinkPos] != End) &&
14509 // (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition))
14510  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
14511  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14512  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos))
14513  {
14514  TrainController->StopTTClockMessage(26, "Can't end a route adjacent to the start of an existing route");
14515  Utilities->CallLogPop(223);
14516  return(false);
14517  }
14518 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
14519 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition))
14520  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
14521  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
14522  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos))
14523  {
14524  TrainController->StopTTClockMessage(27, "Can't end a route adjacent to the start of an existing route");
14525  Utilities->CallLogPop(224);
14526  return(false);
14527  }
14528 // check if adjacent to end of a route & disallow
14530  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition))
14531  {
14532  TrainController->StopTTClockMessage(28, "Can't end a route adjacent to the end of an existing route");
14533  Utilities->CallLogPop(225);
14534  return(false);
14535  }
14536  }
14537 
14538 // check for same route as start element
14540  {
14541  TrainController->StopTTClockMessage(29, "Can't select same route as started in");
14542  Utilities->CallLogPop(226);
14543  return(false);
14544  }
14545 // check for a looping route
14546  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
14547  {
14549  {
14550  TrainController->StopTTClockMessage(69, "Can't create a route that loops back on itself");
14551  Utilities->CallLogPop(1844);
14552  return(false);
14553  }
14554  }
14555 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
14556 // so search from this element. No need to add StartElement to the SearchVector since it already exists in a route
14557 // and don't want to add it again
14558  if(StartSelectionRouteID > -1)
14559  {
14560  if(SearchForPreferredRoute(0, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14561  AutoSigsFlag))
14562  {
14563  SetRouteSearchVectorGraphics(0, AutoSigsFlag, true); // change graphic colour to the route colour
14564  if(PointsToBeChanged(5))
14565  {
14566  PointsChanged = true;
14567  }
14568  Utilities->CallLogPop(227);
14569  return(true);
14570  }
14571  else if(!Track->SuppressRouteFailMessage)
14572  {
14573  //corrected at v2.7.0 - brackets were missed earlier so if SearchForPreferredRoute failed & else condition failed too then returned false with no message
14575  Utilities->CallLogPop(228);
14576  return(false);
14577  }
14578  }
14579  else
14580  {
14581 // Note: StartElement not in an existing route so was added to the searchvector during the earlier function
14582 // First check if selection adjacent to start element and if so use that [can't be as can't have 2 consecutive signals, but leave in]
14583 
14584 // added the XLinkPos checks because of Matt Blades error reported on 28/06/11, where StartElement2 matched EndPosition spuriously
14585 // note that a blank element will have XLinkPos set to -1
14586  if((StartElement1.XLinkPos > -1) && (StartElement1.Conn[StartElement1.XLinkPos] == EndPosition))
14587  {
14588  if(SearchForPreferredRoute(1, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14589  AutoSigsFlag))
14590  {
14591  SetRouteSearchVectorGraphics(1, AutoSigsFlag, true); // change graphic colour to the route colour
14592  if(PointsToBeChanged(6))
14593  {
14594  PointsChanged = true;
14595  }
14596  Utilities->CallLogPop(229);
14597  return(true);
14598  }
14599  else
14600  {
14602  {
14604  }
14605  Utilities->CallLogPop(230);
14606  return(false);
14607  }
14608  }
14609  else if((StartElement2.XLinkPos > -1) && (StartElement2.Conn[StartElement2.XLinkPos] == EndPosition))
14610  {
14611  if(SearchForPreferredRoute(2, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14612  AutoSigsFlag))
14613  {
14614  SetRouteSearchVectorGraphics(2, AutoSigsFlag, true); // change graphic colour to the route colour
14615  if(PointsToBeChanged(7))
14616  {
14617  PointsChanged = true;
14618  }
14619  Utilities->CallLogPop(231);
14620  return(true);
14621  }
14622  else
14623  {
14625  {
14627  }
14628  Utilities->CallLogPop(232);
14629  return(false);
14630  }
14631  }
14632  // now start off in the best direction
14633  int BestPos = Track->FindClosestLinkPosition(0, StartRoutePosition, EndPosition); // can only be 0 or 1
14634  // the following logic is very unstructured as extra bits have been added at different times and I'm reluctant to remove earlier bits in case
14635  // they cover situations that might be overlooked. A full analysis would enable it to be tidied up but it works (so far!) so I'll leave it as it is
14636  // unless new problems are found.
14637  if(StartElement1.XLinkPos == BestPos)
14638  {
14639  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14640  if(SearchForPreferredRoute(3, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14641  AutoSigsFlag))
14642  {
14643  SetRouteSearchVectorGraphics(3, AutoSigsFlag, true); // change graphic colour to the route colour
14644  if(PointsToBeChanged(8))
14645  {
14646  PointsChanged = true;
14647  }
14648  Utilities->CallLogPop(233);
14649  return(true);
14650  }
14651  else if(StartElement2.TrackVectorPosition > -1)
14652  {
14653  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14654  if(SearchForPreferredRoute(4, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14655  AutoSigsFlag))
14656  {
14657  SetRouteSearchVectorGraphics(4, AutoSigsFlag, true); // change graphic colour to the route colour
14658  if(PointsToBeChanged(9))
14659  {
14660  PointsChanged = true;
14661  }
14662  Utilities->CallLogPop(234);
14663  return(true);
14664  }
14665  }
14666  }
14667  else if(StartElement2.TrackVectorPosition > -1)
14668  {
14669  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14670  if(SearchForPreferredRoute(5, StartElement2, StartElement2.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14671  AutoSigsFlag))
14672  {
14673  SetRouteSearchVectorGraphics(6, AutoSigsFlag, true); // change graphic colour to the route colour
14674  if(PointsToBeChanged(10))
14675  {
14676  ;
14677  }
14678  {
14679  PointsChanged = true;
14680  }
14681  Utilities->CallLogPop(1857);
14682  return(true);
14683  }
14684  else if(SearchForPreferredRoute(8, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14685  AutoSigsFlag))
14686  {
14687  SetRouteSearchVectorGraphics(7, AutoSigsFlag, true); // change graphic colour to the route colour
14688  if(PointsToBeChanged(11))
14689  {
14690  ;
14691  }
14692  {
14693  PointsChanged = true;
14694  }
14695  Utilities->CallLogPop(1858);
14696  return(true);
14697  }
14698  }
14699  else if(StartElement1.XLinkPos == (1 - BestPos))
14700  // added at v0.4d to use StartElement1 again with non-Best direction (may be only one & may not point in right direction)
14701  {
14702  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
14703  if(SearchForPreferredRoute(9, StartElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
14704  AutoSigsFlag))
14705  {
14706  SetRouteSearchVectorGraphics(8, AutoSigsFlag, true); // change graphic colour to the route colour
14707  if(PointsToBeChanged(12))
14708  {
14709  PointsChanged = true;
14710  }
14711  Utilities->CallLogPop(1864);
14712  return(true);
14713  }
14714  }
14715  }
14717  {
14719  }
14720  Utilities->CallLogPop(235);
14721  return(false);
14722 }
14723 
14724 // ---------------------------------------------------------------------------
14725 
14726 void TOneRoute::RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
14727 {
14728  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteImageMarker");
14729  if(PrefDirSize() == 0)
14730  {
14731  Utilities->CallLogPop(1704);
14732  return;
14733  }
14734  for(unsigned int x = 0; x < PrefDirSize(); x++)
14735  {
14736  TPrefDirElement TempPrefDirElement = PrefDirVector.at(x);
14737  if(TempPrefDirElement.EXGraphicPtr != 0) // Note: will be 0 if first element or last as leading point
14738  {
14739  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14740  TempPrefDirElement.EXGraphicPtr);
14741  if((TempPrefDirElement.EntryDirectionGraphicPtr != 0) && PrefDirSize() > 1) // Route, no direction if a single element
14742  {
14743  if(x == 0)
14744  {
14745  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14746  TempPrefDirElement.EntryDirectionGraphicPtr);
14747  }
14748  if(x == (PrefDirSize() - 1))
14749  {
14750  Bitmap->Canvas->Draw((TempPrefDirElement.HLoc - Track->GetHLocMin()) * 16, (TempPrefDirElement.VLoc - Track->GetVLocMin()) * 16,
14751  TempPrefDirElement.EntryDirectionGraphicPtr);
14752  }
14753  }
14754  }
14755  }
14756 
14757  Utilities->CallLogPop(1705);
14758 }
14759 
14760 // ---------------------------------------------------------------------------
14761 
14762 bool TOneRoute::SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID,
14763  TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndPosition, bool AutoSigsFlag)
14764 
14765 /*
14766  Brief: similar to SearchForPrefDir but with a PrefDirElement instead of a TrackElement & with additional parameters.
14767  PrefDirElement is the starting element from which to search, it is NOT stored in searchvector during this function. If it's an
14768  element that's not already in a route it will have been stored in SearchVector during GetPreferredRouteStartElement.
14769  ReqPosRouteID is used when RequiredPosition is start of an existing route, else it's -1.
14770  Return false if any element (apart from RequiredPosition) is on an existing route.
14771  Return false if not on a PrefDir with same ELink (can't check XLink as may not be set - if it's a leading point in a recursive call - see later).
14772 
14773  Detail: Function is a continuous loop as examine each element on a potential route, exiting only if find
14774  the required position (return true & leave Searchvector as set up) or if fail (erase all SearchVector entries
14775  added during the function so as to leave it exactly as it was on entering, then return false).
14776  It is a recursive function (similar to SearchForPrefDir) to enable all possible point branches to be searched.
14777  A VectorCount is maintained to count elements added to the SearchVector, so that this number can be erased on failure
14778  of any branch. Enter with starting PrefDirElement & XLinkPos for that element, RequiredPosition - the
14779  TrackVectorPosition of the element to be searched for, ReqPosRouteID -
14780  the route number that the searched-for element is the start of if any, and set to -1 if no
14781  such route. A pointer to EveryPrefDir is also passed in since this is not accessible directly from
14782  this unit, together with the ConsecSignalsRoute and AutoSigsFlag flags.
14783  Create 2 TPrefDirElements - PrefDirElement1 and 2, for use later - ELink has to match the preceding XLink, so the only
14784  2 possible PrefDirs are for a leading point & its two trailing PrefDirs.
14785 
14786  Enter loop - note that PrefDirElement changes each time round the loop - check if PrefDirElement XLinkPos faces buffers
14787  or a continuation, and fail if so. Check if reached a valid next signal in ConsecSignalsRoute on any but firstpass
14788  (nonrecursive firstpass starts at a valid signal, and recursive firstpass always starts at points so doesn't matter
14789  for recursive calls), and fail if so as user should always select the next signal in a route if ConsecSignals set.
14790  Create a new TPrefDirElement - SearchElement, from PrefDirElement.Conn[XLinkPos], & set all FixedTrackPiece &
14791  TrackElement values, ELink & ELinkPos, and also XLink & XLinkPos unless element is a leading point.
14792  Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
14793  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route),
14794  or if train on element (unless a bridge & train on different track).
14795  Check & fail for a fouled diagonal (unless element is a leading point - these checked later).
14796  Check element in EveryPrefDir with same ELink value & set PrefDirElement1, & also 2 if element is
14797  a leading point where both trailing directions are in EveryPrefDir, if not fail.
14798  Check if found RequiredPosition & that it's a signal/buffer/continuation. If OK save in SearchVector with
14799  AutoSignals member set if AutoSigsFlag set, then return true.
14800  Check & fail if a buffer or continuation (unless it is the RequiredPosition, in which case will have succeeded in the above check).
14801 
14802  Now check if a leading point and if so set XLinkPos to the 'set' exit & check if that XLink is in EveryPrefDir,
14803  by comparing with PrefDirElement1 or 2, fail if not. If valid check for a fouled diagonal and fail if so. If OK
14804  store element in SearchVector with AutoSignals member set if AutoSigsFlag set & do a recursive search using
14805  this element and XLinkPos, other parameters are passed in without change. If succeed return true, else erase the last element in
14806  SearchVector (i.e the earlier stored leading point element prior to doing the recursive search) & set XLinkPos to the 'unset' exit to
14807  check the other trailing direction. Then proceed in same way as above, i.e. fouled diagonal & recursive search etc. If
14808  fail on this XLinkPos then have tried & failed on both ways out from the leading point so erase the searchvector & return false.
14809 
14810  If not a leading point store the element (can only be PrefDirElement1 as not a leading point), then set
14811  up the next loop values of PrefDirElement & XLinkPos from SearchElement & NextXLinkPos and repeat the while loop.
14812 */
14813 
14814 {
14815  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForPreferredRoute," + PrefDirElement.LogPrefDir() + "," +
14816  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString(EndPosition) + "," +
14817  AnsiString((short)AutoSigsFlag));
14818  int VectorCount = 0;
14819  TPrefDirElement PrefDirElement1, PrefDirElement2, BlankElement;
14820 
14821 // check for a fouled diagonal for first element. Added for v1.3.2
14822  if((PrefDirElement.XLink == 1) || (PrefDirElement.XLink == 3) || (PrefDirElement.XLink == 7) || (PrefDirElement.XLink == 9))
14823  {
14824  if(AllRoutes->DiagonalFouledByRouteOrTrain(0, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.XLink))
14825  {
14826  for(int x = 0; x < VectorCount; x++)
14827  {
14828  SearchVector.erase(SearchVector.end() - 1);
14829  }
14830  Utilities->CallLogPop(2043);
14831  return(false);
14832  }
14833  }
14834  bool FirstPass = true;
14835 
14836  while(true)
14837  {
14838  if(AutoSigsFlag && Track->IsLCAtHV(24, PrefDirElement.HLoc, PrefDirElement.VLoc))
14839  {
14840  Track->LCFoundInAutoSigsRoute = true;
14841  }
14842  if(Track->IsLCBarrierFlashingAtHV(1, PrefDirElement.HLoc, PrefDirElement.VLoc)) // can't set a route through a flashing barrier
14843  {
14844  for(int x = 0; x < VectorCount; x++)
14845  {
14846  SearchVector.erase(SearchVector.end() - 1);
14847  }
14848  Utilities->CallLogPop(1926);
14849  return(false);
14850  }
14851  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == End) // buffers or continuation
14852  {
14853  for(int x = 0; x < VectorCount; x++)
14854  {
14855  SearchVector.erase(SearchVector.end() - 1);
14856  }
14857  Utilities->CallLogPop(236);
14858  return(false);
14859  }
14860  if(!FirstPass && ConsecSignals && (PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal))
14861  // reached a valid signal that isn't the required position, user should always select the next
14862  // signal in a route so have to fail
14863  // won't affect recurive searches as for them the first pass element is always a point
14864  {
14865  for(int x = 0; x < VectorCount; x++)
14866  {
14867  SearchVector.erase(SearchVector.end() - 1);
14868  }
14869  Utilities->CallLogPop(237);
14870  return(false);
14871  }
14872  FirstPass = false;
14873  int NextPosition = PrefDirElement.Conn[XLinkPos];
14874  TTrackElement NextTrackElement = Track->TrackElementAt(88, NextPosition);
14875  TPrefDirElement SearchElement(NextTrackElement);
14876  SearchElement.TrackVectorPosition = NextPosition;
14877  int NextELinkPos = PrefDirElement.ConnLinkPos[XLinkPos];
14878  SearchElement.ELinkPos = NextELinkPos;
14879  SearchElement.ELink = SearchElement.Link[NextELinkPos]; // Note ELink isn't necessarily 10 - last XLink, as last element may have
14880  // been a gap. Now have all FixedTrackPiece & TrackElement values, + TrackVectorPosition, ELink & ELinkPos
14881  int NextXLinkPos;
14882  if(SearchElement.ELinkPos == 0)
14883  {
14884  NextXLinkPos = 1;
14885  }
14886  if(SearchElement.ELinkPos == 1)
14887  {
14888  NextXLinkPos = 0;
14889  }
14890  if(SearchElement.ELinkPos == 2)
14891  {
14892  NextXLinkPos = 3;
14893  }
14894  if(SearchElement.ELinkPos == 3)
14895  {
14896  NextXLinkPos = 2;
14897  }
14898  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
14899  {
14900  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
14901 // note that may be buffers, continuation or gap
14902  SearchElement.XLinkPos = NextXLinkPos;
14903  }
14904 // can't set XLink or XLinkPos yet if the element is a leading point.
14905 
14906 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
14907  for(unsigned int x = 0; x < SearchVector.size(); x++)
14908  {
14909  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
14910  {
14911  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
14912  // OK if a bridge & routes on different tracks
14913  {
14914  for(int x = 0; x < VectorCount; x++)
14915  {
14916  SearchVector.erase(SearchVector.end() - 1);
14917  }
14918  Utilities->CallLogPop(238);
14919  return(false);
14920  }
14921  }
14922  }
14923 
14924 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
14925  TAllRoutes::TRouteElementPair SecondPair;
14927  Track->TrackElementAt(89, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(90, SearchElement.TrackVectorPosition).VLoc, SecondPair);
14928  if(RoutePair.first > -1)
14929  {
14930  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14931  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(12, RoutePair.first).GetFixedPrefDirElementAt(38,
14932  RoutePair.second).ELinkPos)))
14933  {
14934  // still OK if start of an expected route
14935  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(2, ReqPosRouteID)) || (RoutePair.second != 0))
14936  {
14937  for(int x = 0; x < VectorCount; x++)
14938  {
14939  SearchVector.erase(SearchVector.end() - 1);
14940  }
14941  Utilities->CallLogPop(239);
14942  return(false); // only allow for start of an expected route
14943  }
14944  }
14945  }
14946  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
14947  {
14948  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
14949  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(13, SecondPair.first).GetFixedPrefDirElementAt(39,
14950  SecondPair.second).ELinkPos)))
14951  {
14952  // still OK if start of an expected route
14953  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(3, ReqPosRouteID)) || (SecondPair.second != 0))
14954  {
14955  for(int x = 0; x < VectorCount; x++)
14956  {
14957  SearchVector.erase(SearchVector.end() - 1);
14958  }
14959  Utilities->CallLogPop(240);
14960  return(false); // only allow for start of an expected route
14961  }
14962  }
14963  }
14964 // check if a train on element, unless a bridge & train on different track
14965 // OK of same train as start element - no drop this
14966 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
14967  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
14968  {
14969  for(int x = 0; x < VectorCount; x++)
14970  {
14971  SearchVector.erase(SearchVector.end() - 1);
14972  }
14973  Utilities->CallLogPop(241);
14974  return(false);
14975  }
14976  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
14977  {
14978  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
14979  {
14980  for(int x = 0; x < VectorCount; x++)
14981  {
14982  SearchVector.erase(SearchVector.end() - 1);
14983  }
14984  Utilities->CallLogPop(242);
14985  return(false);
14986  }
14987  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
14988  {
14989  for(int x = 0; x < VectorCount; x++)
14990  {
14991  SearchVector.erase(SearchVector.end() - 1);
14992  }
14993  Utilities->CallLogPop(243);
14994  return(false);
14995  }
14996  }
14997 // check for a fouled diagonal (if not leading point - these checked later - leading point XLink == -1)
14998  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
14999  {
15000  if(AllRoutes->DiagonalFouledByRouteOrTrain(7, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15001  {
15002  for(int x = 0; x < VectorCount; x++)
15003  {
15004  SearchVector.erase(SearchVector.end() - 1);
15005  }
15006  Utilities->CallLogPop(244);
15007  return(false);
15008  }
15009  }
15010 // check element in EveryPrefDir with same ELink (XLink may not be set) & save up to 2 elements (for leading point & 2 trailing PrefDirs)
15011 // note that point XLinks checked later, otherwise XLink fully defined by ELink so only need to check ELink
15012  bool InPrefDirFlag = false;
15013  PrefDirElement1 = BlankElement;
15014  PrefDirElement2 = BlankElement;
15015 
15016  bool FoundFlag;
15017  int PrefDirPos0 = -1;
15018  int PrefDirPos1 = -1;
15019  int PrefDirPos2 = -1;
15020  int PrefDirPos3 = -1;
15022  Track->TrackElementAt(92, SearchElement.TrackVectorPosition).VLoc, FoundFlag, PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3);
15023  int PrefDirVecPos[4] =
15024  {
15025  PrefDirPos0, PrefDirPos1, PrefDirPos2, PrefDirPos3
15026  };
15027  for(int x = 0; x < 4; x++)
15028  {
15029  int b = PrefDirVecPos[x];
15030  if((b > -1) && (EveryPrefDir->GetFixedPrefDirElementAt(40, b).ELink == SearchElement.ELink))
15031  {
15032  InPrefDirFlag = true;
15033  if(PrefDirElement1.TrackVectorPosition == -1)
15034  {
15035  PrefDirElement1 = EveryPrefDir->GetFixedPrefDirElementAt(41, b);
15036  }
15037  else
15038  {
15039  PrefDirElement2 = EveryPrefDir->GetFixedPrefDirElementAt(42, b);
15040  }
15041  }
15042  }
15043  if(!InPrefDirFlag)
15044  {
15045  for(int x = 0; x < VectorCount; x++)
15046  {
15047  SearchVector.erase(SearchVector.end() - 1);
15048  }
15049  Utilities->CallLogPop(245);
15050  return(false);
15051  }
15052 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
15053 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
15054 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
15056  {
15057  for(int x = 0; x < VectorCount; x++)
15058  {
15059  SearchVector.erase(SearchVector.end() - 1);
15060  }
15061  Utilities->CallLogPop(1690);
15062  return(false);
15063  }
15064 // check if found it
15065  if(SearchElement.TrackVectorPosition == RequiredPosition)
15066  {
15067 // need to ensure a signal/buffer/continuation
15068  if((SearchElement.Config[SearchElement.XLinkPos] != Signal) && (SearchElement.Config[SearchElement.XLinkPos] != End) &&
15069  (SearchElement.Config[SearchElement.XLinkPos] != Continuation))
15070  {
15071  TrainController->StopTTClockMessage(94, "Must select a valid signal, buffers or continuation"); //added at v2.7.0
15073  for(int x = 0; x < VectorCount; x++)
15074  {
15075  SearchVector.erase(SearchVector.end() - 1);
15076  }
15077  Utilities->CallLogPop(246);
15078  return(false);
15079  } // if((SearchElement.Config[SearchElement.XLinkPos] != Signal).......
15080 
15081  if(AutoSigsFlag)
15082  {
15083  PrefDirElement1.AutoSignals = true;
15084  }
15085  PrefDirElement1.PrefDirRoute = true;
15087  {
15089  {
15090  TrainController->StopTTClockMessage(76, "Can't create an automatic signal route through a level crossing");
15092  }
15093  for(int x = 0; x < VectorCount; x++)
15094  {
15095  SearchVector.erase(SearchVector.end() - 1);
15096  }
15097  Utilities->CallLogPop(1928);
15098  return(false);
15099  }
15100  SearchVector.push_back(PrefDirElement1); // must be 1 as it's a simple element
15101  VectorCount++; // not really needed but include for tidyness
15102  TotalSearchCount++;
15103  Utilities->CallLogPop(247);
15104  return(true);
15105  } // if(SearchElement.TrackVectorPosition == RequiredPosition)
15106 
15107 // check if a buffer or continuation (end of search on this leg if not found by now)
15108  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
15109  {
15110  for(int x = 0; x < VectorCount; x++)
15111  {
15112  SearchVector.erase(SearchVector.end() - 1);
15113  }
15114  Utilities->CallLogPop(248);
15115  return(false);
15116  }
15117 // check if SearchVector exceeds a size of 150
15118  if(SearchVector.size() > 150)
15119  {
15120  for(int x = 0; x < VectorCount; x++)
15121  {
15122  SearchVector.erase(SearchVector.end() - 1);
15123  }
15124  Utilities->CallLogPop(1420);
15125  return(false);
15126  }
15127 // check if reached a leading point
15128  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
15129  {
15130 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
15131  int SearchPos1 = SearchElement.Attribute + 1;
15132  int SearchPos2;
15133  if(SearchPos1 == 2)
15134  {
15135  SearchPos1++;
15136  }
15137  if(SearchPos1 == 1)
15138  {
15139  SearchPos2 = 3;
15140  }
15141  else
15142  {
15143  SearchPos2 = 1;
15144  }
15145  SearchElement.XLink = SearchElement.Link[SearchPos1];
15146  SearchElement.XLinkPos = SearchPos1;
15147  InPrefDirFlag = false;
15148  if(SearchElement.XLink == PrefDirElement1.XLink)
15149  {
15150  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15151  InPrefDirFlag = true;
15152  }
15153  else if(SearchElement.XLink == PrefDirElement2.XLink)
15154  {
15155  SearchElement = PrefDirElement2;
15156  InPrefDirFlag = true;
15157  }
15158 // push element with XLink set to position [SearchPos1] if on a PrefDir
15159  if(InPrefDirFlag)
15160  {
15161 // check for a fouled diagonal for leading point for XLinkPos == 1)
15162  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15163  {
15164  if(AllRoutes->DiagonalFouledByRouteOrTrain(1, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15165  {
15166  for(int x = 0; x < VectorCount; x++)
15167  {
15168  SearchVector.erase(SearchVector.end() - 1);
15169  }
15170  Utilities->CallLogPop(249);
15171  return(false);
15172  }
15173  }
15174  if(AutoSigsFlag)
15175  {
15176  SearchElement.AutoSignals = true;
15177  }
15178  SearchElement.PrefDirRoute = true;
15179  SearchVector.push_back(SearchElement);
15180  VectorCount++;
15181  TotalSearchCount++;
15182 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
15183  if(SearchForPreferredRoute(6, SearchElement, SearchPos1, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15184  AutoSigsFlag))
15185  {
15187  {
15189  {
15190  TrainController->StopTTClockMessage(77, "Can't create an automatic signal route through a level crossing");
15192  }
15193  for(int x = 0; x < VectorCount; x++)
15194  {
15195  SearchVector.erase(SearchVector.end() - 1);
15196  }
15197  Utilities->CallLogPop(1929);
15198  return(false);
15199  }
15200  Utilities->CallLogPop(250);
15201  return(true);
15202  }
15203  else
15204  {
15205 // remove leading point with XLinkPos [1]
15206  SearchVector.erase(SearchVector.end() - 1);
15207  VectorCount--;
15208  }
15209  }
15210 // XLink set to position [SearchPos2]
15211  SearchElement.XLink = SearchElement.Link[SearchPos2];
15212  SearchElement.XLinkPos = SearchPos2;
15213  if(SearchElement.XLink == PrefDirElement1.XLink)
15214  {
15215  SearchElement = PrefDirElement1; // set to an existing PrefDir element so that exnumber & graphics set
15216  }
15217  else if(SearchElement.XLink == PrefDirElement2.XLink)
15218  {
15219  SearchElement = PrefDirElement2;
15220  }
15221  else // failed to find a valid exit from the point
15222  {
15223  for(int x = 0; x < VectorCount; x++)
15224  {
15225  SearchVector.erase(SearchVector.end() - 1);
15226  }
15227  Utilities->CallLogPop(251);
15228  return(false);
15229  }
15230 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
15231  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
15232  {
15233  if(AllRoutes->DiagonalFouledByRouteOrTrain(2, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
15234  {
15235  for(int x = 0; x < VectorCount; x++)
15236  {
15237  SearchVector.erase(SearchVector.end() - 1);
15238  }
15239  Utilities->CallLogPop(252);
15240  return(false);
15241  }
15242  }
15243 // push element with XLink set to position [SearchPos2]
15244  if(AutoSigsFlag)
15245  {
15246  SearchElement.AutoSignals = true;
15247  }
15248  SearchElement.PrefDirRoute = true;
15249  SearchVector.push_back(SearchElement);
15250  VectorCount++;
15251  TotalSearchCount++;
15252 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
15253  if(SearchForPreferredRoute(7, SearchElement, SearchPos2, RequiredPosition, ReqPosRouteID, EveryPrefDir, ConsecSignals, EndPosition,
15254  AutoSigsFlag))
15255  {
15257  {
15259  {
15260  TrainController->StopTTClockMessage(78, "Can't create an automatic signal route through a level crossing");
15262  }
15263  for(int x = 0; x < VectorCount; x++)
15264  {
15265  SearchVector.erase(SearchVector.end() - 1);
15266  }
15267  Utilities->CallLogPop(1930);
15268  return(false);
15269  }
15270  Utilities->CallLogPop(1592);
15271  return(true);
15272  }
15273  else
15274  {
15275  for(int x = 0; x < VectorCount; x++)
15276  {
15277  SearchVector.erase(SearchVector.end() - 1);
15278  }
15279  Utilities->CallLogPop(253);
15280  return(false);
15281  }
15282  } // if leading point
15283 
15284 // here if ordinary element, push it, inc vector & update PrefDirElement ready for next element on PrefDir
15285  SearchElement = PrefDirElement1;
15286  if(AutoSigsFlag)
15287  {
15288  SearchElement.AutoSignals = true;
15289  }
15290  SearchElement.PrefDirRoute = true;
15291  SearchVector.push_back(SearchElement);
15292  VectorCount++;
15293  TotalSearchCount++;
15294  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
15295  PrefDirElement = SearchElement;
15296  } // while(true)
15297 }
15298 
15299 // ---------------------------------------------------------------------------
15300 
15301 void TOneRoute::ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
15302 {
15303 /*
15304  For routes, as opposed to PrefDirs, the new route elements are first entered into SearchVector,
15305  and the new or extended route created from that. Hence action varies depending on whether
15306  it is a completely new route, or an extension of an existing route at the beginning or the end.
15307  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
15308  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
15309 
15310  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
15311  Check if route end selection is in an existing route (ReqPosRouteID > -1), and if so proceed as follows:-
15312  if both new and existing routes non-autosig, add the old route to the SearchVector then delete the old route;
15313  if both new and existing routes autosig, add the old route to the SearchVector then delete the old route;
15314  in both the above cases if RequPosRouteNumber is less than StartSelectionRouteNumber then StartSelectionRouteNumber
15315  is decremented;
15316  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element)
15317  from the existing route, then enter the new route into the AllRoutesVector;
15318  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15319  then enter the new route into the AllRoutesVector.
15320 
15321  Check if StartSelectionRouteID set (extending an existing route) and if so proceed as follows:-
15322  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector);
15323  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector);
15324  in both the above cases validate the extended route, then call SetRoutePoints & SetRouteSignals for the extended route and return.
15325  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15326  then add it to the start of the new route, then check its validity, enter it into the AllRoutesVector, call SetRoutePoints & SetRouteSignals
15327  for the new route and return;
15328  if new route non-autosig and existing route autosig, leave the existing route as it is, check its validity, then just enter the new
15329  route into the AllRoutesVector, finally call SetRoutePoints & SetRouteSignals for the new route and return.
15330 
15331  If not returned by now the route in SearchVector is to be added as a new route, so check its validity, create a new route using
15332  StoreOneRoute, call SetRoutePoints & SetRouteSignals and return. In practice the validity check, storage into AllRoutesVector and
15333  SetRoutePoints & SetRouteSignals call are combined for the above three cases.
15334 
15335 */
15336  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddPreferredRouteSearchVector," +
15337  AnsiString(ReqPosRouteID.GetInt()) + "," + AnsiString((short)AutoSigsFlag));
15338  if(SearchVector.size() < 1)
15339  {
15340  Utilities->CallLogPop(254);
15341  return;
15342  }
15344  if(!ValidatePrefDir(3)) // check the new route elements in SearchVector
15345  {
15346  Utilities->CallLogPop(255);
15347  return;
15348  }
15349  TAllRoutes::TLockedRouteClass LockedRouteObject;
15350 
15352  unsigned int TruncatePrefDirPosition = 0;
15353 
15354  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartRouteNumber as would have failed in GetNextRouteElement
15355 /* if have ReqPosRouteID:
15356  if both new and existing routes non-autosig, then add the old route to the SearchVector then delete the old route
15357  if both new and existing routes autosig, then add the old route to the SearchVector then delete the old route
15358  if new route autosig and existing route non-autosig, keep the final search element in the new route & remove it (i.e first element) from
15359  the existing route, then enter the new route into the AllRoutesVector
15360  if new route non-autosig and existing route autosig, drop the final search element in the new route, leave the existing route as it is,
15361  then enter the new route into the AllRoutesVector
15362 */
15363  {
15366  {
15367  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(21, ReqPosRouteID).PrefDirSize();
15368  x++) // start at 1 as first element already in SearchVector
15369  {
15371  }
15372  // note that route numbers in map adjusted when ReqPos route cleared
15374  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
15375  // set during ClearRouteDuringRouteBuildingAt
15377  {
15380  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
15381  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
15382  }
15383  }
15385  {
15387  AllRoutes->RemoveRouteElement(3, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15388  }
15390  {
15391  SearchVector.pop_back();
15392  }
15393  }
15394  if(StartSelectionRouteID > -1)
15395 /* if have StartSelectionRouteID:
15396  if both new and existing routes non-autosig, then add the new route to the existing route (start element not stored in searchvector)
15397  if both new and existing routes autosig, then add the new route to the existing route (start element not stored in searchvector)
15398  if new route autosig and existing route non-autosig, remove the last route element from the existing route, make it an AutoSig element,
15399  then add it to the start of the new route, then enter the new route into the AllRoutesVector
15400  if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
15401 */
15402  {
15404  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
15405  {
15408  {
15409  int RouteNumber = AllRoutes->GetRouteVectorNumber(0, StartSelectionRouteID);
15410  for(unsigned int x = 0; x < SearchVector.size(); x++)
15411  {
15413  RouteNumber, GetFixedSearchElementAt(3, x));
15414  // find & store locked route truncate position in PrefDirVector for later use
15416  {
15417  if(GetFixedSearchElementAt(15, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
15418  {
15419  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(172, RouteNumber).PrefDirSize() - 1;
15420  }
15421  }
15422  }
15424  {
15425  throw Exception("Error - failed to validate extended route for preferred route");
15426  }
15429  if(!AutoSigsFlag)
15430  {
15431  AllRoutes->GetModifiableRouteAtIDNumber(7, StartSelectionRouteID).SetLCChangeValues(0, true); // ConsecSignalsRoute is true
15432  }
15433  // now add the reinstated locked route if required and set signals accordingly
15435  {
15436  LockedRouteObject.RouteNumber = RouteNumber;
15437  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
15438  // now reset the signals for the locked route
15439  AllRoutes->SetAllRearwardsSignals(9, 0, RouteNumber, TruncatePrefDirPosition);
15440  for(int c = AllRoutes->GetFixedRouteAt(173, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
15441  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
15442  {
15443  // return all signals to red in route section to be truncated
15444  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(174, RouteNumber).PrefDirVector.at(c);
15445  TTrackElement & TrackElement = Track->TrackElementAt(812, PrefDirElement.TrackVectorPosition);
15446  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
15447  {
15448  TrackElement.Attribute = 0;
15449  Track->PlotSignal(10, TrackElement, Display);
15450  Display->PlotOutput(113, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
15451  Display->PlotOutput(114, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
15452  }
15453  }
15454  }
15455  AllRoutes->CheckMapAndRoutes(1); // test
15456  Utilities->CallLogPop(256);
15457  return;
15458  }
15460  {
15463  RouteElement.AutoSignals = true;
15464  RouteElement.EXGraphicPtr = RouteElement.GetRouteGraphicPtr(AutoSigsFlag, true);
15465  RouteElement.EntryDirectionGraphicPtr = RouteElement.GetDirectionRouteGraphicPtr(AutoSigsFlag, true); // as above
15466  AllRoutes->RemoveRouteElement(4, RouteElement.HLoc, RouteElement.VLoc, RouteElement.ELink);
15467  SearchVector.insert(SearchVector.begin(), 1, RouteElement);
15468  }
15469  }
15470  else
15471  {
15473  }
15474 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the
15475 // AllRoutesVector hence nothing to do here
15476  }
15477  PrefDirVector = SearchVector; // need to copy again since SearchVector may have been extended
15478  if(!ValidatePrefDir(5)) // validate PrefDir for all new route elements
15479  {
15480  throw Exception("Error - failed to validate single route for preferred route");
15481  }
15482  AllRoutes->StoreOneRoute(1, this);
15483  AllRoutes->GetModifiableRouteAt(3, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(1); // new addition
15484  AllRoutes->GetModifiableRouteAt(16, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(5); // new addition
15485  if(!AutoSigsFlag)
15486  {
15487  AllRoutes->GetModifiableRouteAt(18, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(1, true); // ConsecSignalsRoute is true
15488  }
15489  AllRoutes->CheckMapAndRoutes(2); // test
15490  Utilities->CallLogPop(257);
15491 }
15492 
15493 // ---------------------------------------------------------------------------
15494 
15495 bool TOneRoute::GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon) // Return true if OK.
15496 {
15497 /*
15498  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15499  Clear the PrefDir and search vectors using ClearRoute(). Check selection matches a TrackElement
15500  & ensure signal/buffers/continuation.
15501  Note that can't select ConsecSignalsRoute for non-preferred routes.
15502  Check if train on element & disallow.
15503  Set default values for retained parameters:-
15504  StartRoutePosition = TrackVectorPosition of the element to be used as the start of the route;
15505  StartSelectionRouteID = route that selection starts in if there is one;
15506 
15507  Create 2 PrefDirElements from the TrackElement, setting all values corresponding to the 2 possible PrefDirs
15508  through the element (can only be 2 as 3 & 4 ended elements aren't allowed) & make an EXNumber check for
15509  validity. This is just for safety reasons, the PrefDir values aren't used.
15510  StartElement1 & 2 are set to these PrefDirelements.
15511 
15512  There is no need to check that the element lies in a PrefDir for nonpreferred selections.
15513 
15514  Check if in an existing route & if so only allow last element to be selected - ensure it has somewhere to go!
15515  Set StartElement1, StartSelectionRouteID and StartRoutePosition to correspond to the route end element and
15516  blank StartElement2 (only want to use the route element), then return true.
15517  Check if adjacent to start or end of an existing route & disallow if so.
15518  If not in a route and not failed so far then reset all Link, all LinkPos, & EXNumber values to -1, and CheckCount
15519  to 4 for StartElement1, & blank StartElement2. The remaining data members will be set later in
15520  SetRemainingSearchVectorValues().
15521  Finally add the required element to the SearchVector & return true.
15522 
15523 */
15524  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNonPreferredRouteStartElement," + AnsiString(HLoc) + "," +
15525  AnsiString(VLoc) + "," + AnsiString((short)Callon));
15526  ClearRoute();
15527  int TrackVectorPosition;
15528  TTrackElement TrackElement;
15529  TPrefDirElement FirstElement, LastElement;
15530 
15531  if(!(Track->FindNonPlatformMatch(9, HLoc, VLoc, TrackVectorPosition, TrackElement)))
15532  {
15533  Utilities->CallLogPop(258);
15534  return(false);
15535  }
15536  if((TrackElement.TrackType == Points) || (TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15537  {
15538  if(!Callon)
15539  {
15540  TrainController->StopTTClockMessage(34, "Can't select points, bridge or crossover when route building");
15541  }
15542 // makes later adjacent route checks too complicated
15543  Utilities->CallLogPop(259);
15544  return(false);
15545  }
15546  if(Track->IsLCAtHV(21, HLoc, VLoc))
15547  {
15548  TrainController->StopTTClockMessage(74, "Can't start a route on a level crossing");
15549  Utilities->CallLogPop(1910);
15550  return(false);
15551  }
15552 // check if selected a train & disallow if so
15553  if(TrackElement.TrainIDOnElement > -1)
15554  {
15555  if(!Callon)
15556  {
15557  TrainController->StopTTClockMessage(35, "Can't start a route on a train");
15558  }
15559  Utilities->CallLogPop(260);
15560  return(false);
15561  }
15562 // check if selected a locked route element & disallow (can only be a 2-track element so only need check XLinkPos values of 0 & 1
15563  TPrefDirElement PrefDirElement;
15564  int LockedVectorNumber;
15565 
15566  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(3, TrackVectorPosition, 0, PrefDirElement, LockedVectorNumber))
15567  {
15568  if(!Callon)
15569  {
15570  TrainController->StopTTClockMessage(36, "Can't start a route on a locked route");
15571  }
15572  Utilities->CallLogPop(261);
15573  return(false);
15574  }
15575  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(4, TrackVectorPosition, 1, PrefDirElement, LockedVectorNumber))
15576  {
15577  if(!Callon)
15578  {
15579  TrainController->StopTTClockMessage(37, "Can't start a route on a locked route");
15580  }
15581  Utilities->CallLogPop(262);
15582  return(false);
15583  }
15585 // AdjacentStartRouteNumber = -1;
15586  StartRoutePosition = TrackVectorPosition;
15587 // StartRouteSelectPosition = TrackVectorPosition;
15588 
15589  TPrefDirElement PrefDirElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15590  TPrefDirElement PrefDirElement2(TrackElement);
15591 
15592  PrefDirElement1.TrackVectorPosition = TrackVectorPosition;
15593  PrefDirElement2.TrackVectorPosition = TrackVectorPosition;
15594  TPrefDirElement BlankElement;
15595 
15596  PrefDirElement1.ELinkPos = 0;
15597  PrefDirElement1.XLinkPos = 1;
15598  PrefDirElement1.ELink = PrefDirElement1.Link[0];
15599  PrefDirElement1.XLink = PrefDirElement1.Link[1];
15600  if(!(PrefDirElement1.EntryExitNumber()))
15601  {
15602  throw Exception("Error, No EXNumber for PrefDirElement1 in GetNonPreferredRouteStartElement");
15603  // no need for bridge check as bridge selections not allowed
15604  }
15605  PrefDirElement1.CheckCount = 9;
15606  PrefDirElement2.ELinkPos = 1;
15607  PrefDirElement2.XLinkPos = 0;
15608  PrefDirElement2.ELink = PrefDirElement2.Link[1];
15609  PrefDirElement2.XLink = PrefDirElement2.Link[0];
15610  if(!(PrefDirElement2.EntryExitNumber()))
15611  {
15612  throw Exception("Error, No EXNumber for PrefDirElement2 in GetNonPreferredRouteStartElement");
15613  }
15614  PrefDirElement2.CheckCount = 9; // both now set
15615 
15616 // set StartElements to the above PrefDirElements
15617  StartElement1 = PrefDirElement1;
15618  StartElement2 = PrefDirElement2;
15619 
15620 // no PrefDir check needed as doesn't need to be in a PrefDir
15621 
15622 // look for exact match in a route first - can't be a 3 or 4 track element so only need to look for one TRouteElementPair
15624  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(1, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15625 
15626  if(RoutePair.first > -1)
15627  {
15628  if(RoutePair.second != AllRoutes->GetFixedRouteAt(31, RoutePair.first).PrefDirSize() - 1) // not last element in existing route so no good
15629  {
15630  if(!Callon)
15631  {
15632  TrainController->StopTTClockMessage(38, "Can't start a route within or at the start of an existing route");
15633  }
15634  Utilities->CallLogPop(263);
15635  return(false);
15636  }
15637  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(32, RoutePair.first).GetFixedPrefDirElementAt(56, RoutePair.second);
15638  if(RouteElement.Conn[RouteElement.XLinkPos] < 0) // last element in existing route but nowhere to go!
15639  {
15640  if(!Callon)
15641  {
15642  TrainController->StopTTClockMessage(39, "No forward connection from this position");
15643  }
15644  Utilities->CallLogPop(264);
15645  return(false);
15646  }
15647  if((RouteElement.Config[RouteElement.XLinkPos] != End) && (AllRoutes->TrackIsInARoute(11, RouteElement.Conn[RouteElement.XLinkPos],
15648  RouteElement.ConnLinkPos[RouteElement.XLinkPos])))
15649  // last element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15650  {
15651  if(!Callon)
15652  {
15653  TrainController->StopTTClockMessage(40, "Can't start a route at an element that links forward into an existing route");
15654  }
15655  Utilities->CallLogPop(265);
15656  return(false);
15657  }
15658  StartSelectionRouteID = IDInt(AllRoutes->GetFixedRouteAt(162, RoutePair.first).RouteID);
15660  AllRoutes->GetFixedRouteAt(34, RoutePair.first).PrefDirSize() - 1); // last element
15661  StartElement2 = BlankElement; // only use the route element
15663  Utilities->CallLogPop(266);
15664  return(true); // all retained values set
15665  }
15666 
15667  else // selection not in an existing route
15668  {
15669 // check if it's adjacent to start of an an existing route,
15670  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15671  {
15672  FirstElement = AllRoutes->GetFixedRouteAt(35, a).GetFixedPrefDirElementAt(58, 0);
15673  if((StartElement1.Conn[0] > -1) && (StartElement1.Conn[0] == FirstElement.TrackVectorPosition))
15674  {
15675  if(!Callon)
15676  {
15677  TrainController->StopTTClockMessage(41, "Can't make selection adjacent to start of another route");
15678  }
15679  Utilities->CallLogPop(267);
15680  return(false);
15681  }
15682  if((StartElement1.Conn[1] > -1) && (StartElement1.Conn[1] == FirstElement.TrackVectorPosition))
15683  {
15684  if(!Callon)
15685  {
15686  TrainController->StopTTClockMessage(42, "Can't make selection adjacent to start of another route");
15687  }
15688  Utilities->CallLogPop(268);
15689  return(false);
15690  }
15691  }
15692 // check if it's adjacent to end of an an existing route,
15693  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15694  {
15696  if(LastElement.Conn[LastElement.XLinkPos] == StartRoutePosition)
15697  {
15698  if(!Callon)
15699  {
15700  TrainController->StopTTClockMessage(43, "Can't start a route adjacent to the end of an existing route");
15701  }
15702  Utilities->CallLogPop(269);
15703  return(false);
15704  }
15705  }
15706  // not in a route or adjacent to start or end of a route
15707  // in this case reset all variable values to -1 & CheckCount to 4
15708  StartElement1.ELink = -1;
15709  StartElement1.ELinkPos = -1;
15710  StartElement1.XLink = -1;
15711  StartElement1.XLinkPos = -1;
15712  StartElement1.EXNumber = -1;
15714  StartElement2 = BlankElement;
15715  SearchVector.push_back(StartElement1);
15716  Utilities->CallLogPop(270);
15717  return(true);
15718  }
15719 }
15720 
15721 // ---------------------------------------------------------------------------
15722 bool TOneRoute::GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
15723 
15724 /*
15725  If Callon true then this routine is called from MainScreenMouseDown2 in InterfaceUnit.cpp to set an unrestricted call-on route - messages are suppressed
15726 
15727  Declare the following integers:-
15728  EndPosition - TrackVectorPosition for the selection;
15729  ReqPosRouteID - for the existing route selected if there is one, set to -1 if not;
15730  Check if selection is a valid track element and set EndPosition.
15731  Cancel if select original start element, then check that not points, bridge or crossover.
15732  Check & fail if a train is present at the selection.
15733  Create & set 2 PrefDirElements EndElement1 & 2 corresponding to the 2 possible PrefDir elements (similar to StartElement1 & 2
15734  in GetNonPreferredRouteStartElement) & make an EXNumber validity check just for safety reasons - the PrefDir values are not used.
15735  No check needed for selection in EveryPrefDir.
15736  Check if selection in an existing route & if so ensure it's the start element and that it doesn't have an 'End' facing the start.
15737  If it is the start of a route set ReqPosRouteID, EndPosition & EndElement1 to the start of route values and blank EndElement2
15738  as don't need it if in a route.
15739  Check if selection adj to start or end of a route and disallow.
15740  Fail if select same route as starting route, though should already have failed earlier if this is so.
15741 
15742  If there's a StartSelectionRouteID then StartElement1 will be set to
15743  the last entry in the selected route so use SearchForNonPreferredRoute to search for the selected end element from this
15744  start element. If succeed then complete the search vector values (since not on a PrefDir) & return true, for Interface
15745  to handle the flashing & time delay. After the delay completes the Interface flasher calls ConvertAndAddNonPreferredRouteSearchVector
15746  to add the new route to the AllRoutesVectorPtr.
15747  If no starting route then StartElement1 only has basic values set & is in the SearchVector, and StartElement2 is blank.
15748  Check if the selected element is adjacent to the starting position and if so set the route to go directly to it (as opposed to
15749  going round a long loop to get to it just because that XLinkPos happens to be chosen first).
15750  If not adjacent then search on the two possible ways out of StartElement1 providing it isn't facing an 'End'. If succeed complete
15751  the search vector values and return.
15752  If not returned yet then have failed to find the required element so return false with no message.
15753 
15754 */
15755 
15756 {
15757 // get EndPosition
15758  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetNextNonPreferredRouteElement," + AnsiString(HLoc) + "," +
15759  AnsiString(VLoc));
15760  int EndPosition;
15761 
15762  TotalSearchCount = 0;
15763  ReqPosRouteID = IDInt(-1); // for not used
15764  TTrackElement TrackElement;
15765  TPrefDirElement BlankElement;
15766 
15767  if(!(Track->FindNonPlatformMatch(10, HLoc, VLoc, EndPosition, TrackElement))) // return if can't find one
15768  {
15769  Utilities->CallLogPop(271);
15770  return(false);
15771  }
15772 // EndPosition = EndSelectPosition;
15773 // cancel selection if on original start element
15774  if(EndPosition == StartRoutePosition)
15775  {
15776  Utilities->CallLogPop(272);
15777  return(false);
15778  }
15779  if(Track->IsLCAtHV(22, HLoc, VLoc))
15780  {
15781  TrainController->StopTTClockMessage(75, "Can't end a route on a level crossing");
15782  Utilities->CallLogPop(1911);
15783  return(false);
15784  }
15785  if((TrackElement.TrackType == Points) && !Callon)
15786  {
15787  if(!Callon)
15788  {
15789  TrainController->StopTTClockMessage(44, "Can't select points, bridge or crossover when route building");
15790  }
15791 // makes later adjacent route checks too complicated
15792  Utilities->CallLogPop(273);
15793  return(false);
15794  }
15795  if((TrackElement.TrackType == Bridge) || (TrackElement.TrackType == Crossover))
15796  {
15797  if(!Callon)
15798  {
15799  TrainController->StopTTClockMessage(71, "Can't select points, bridge or crossover when route building");
15800  }
15801 // makes later adjacent route checks too complicated
15802  Utilities->CallLogPop(1861);
15803  return(false);
15804  }
15805 // check if train on element
15806  if(TrackElement.TrainIDOnElement > -1)
15807  {
15808  if(!Callon)
15809  {
15810  TrainController->StopTTClockMessage(45, "Can't end a route on a train");
15811  }
15812  Utilities->CallLogPop(274);
15813  return(false);
15814  }
15815 // set the 2 EndElements corresponding to the 2 possible PrefDirs for the selected element (for safety reasons - to ensure EXNumber validity
15816 // check passed)
15817  TPrefDirElement EndElement1(TrackElement); // 1 & 2 for the 2 possible PrefDirs at this location
15818  TPrefDirElement EndElement2(TrackElement);
15819 
15820  EndElement1.TrackVectorPosition = EndPosition;
15821  EndElement2.TrackVectorPosition = EndPosition;
15822  EndElement1.ELinkPos = 0;
15823  EndElement1.XLinkPos = 1;
15824  EndElement1.ELink = EndElement1.Link[0];
15825  EndElement1.XLink = EndElement1.Link[1];
15826  if(!(EndElement1.EntryExitNumber()))
15827  {
15828  throw Exception("Error, No EXNumber for EndElement1 in GetNonPreferredRouteStartElement");
15829  }
15830  EndElement1.CheckCount = 9;
15831  EndElement2.ELinkPos = 1;
15832  EndElement2.XLinkPos = 0;
15833  EndElement2.ELink = EndElement2.Link[1];
15834  EndElement2.XLink = EndElement2.Link[0];
15835  if(!(EndElement2.EntryExitNumber()))
15836  {
15837  throw Exception("Error, No EXNumber for EndElement2 in GetNonPreferredRouteStartElement");
15838  }
15839  EndElement2.CheckCount = 9; // both now set
15840 
15841 // set the H&V limits for the search, all points on search path must lie within 15 elements greater than the box of which the line between
15842 // start and finish is a diagonal line [dropped as not a good strategy because gaps interfered with direct line searches - instead
15843 // introduced TotalSearchCount and now use that to limit searches. Leave in though in case rethink strategy later on]
15844 
15845  if(EndElement1.HLoc >= StartElement1.HLoc)
15846  {
15848  SearchLimitHighH = EndElement1.HLoc + 15;
15849  }
15850  else
15851  {
15852  SearchLimitLowH = EndElement1.HLoc - 15;
15854  }
15855  if(EndElement1.VLoc >= StartElement1.VLoc)
15856  {
15858  SearchLimitHighV = EndElement1.VLoc + 15;
15859  }
15860  else
15861  {
15862  SearchLimitLowV = EndElement1.VLoc - 15;
15864  }
15865 /* dropped this for v0.4d - prevents ability to set routes for gaps that are widely separated, ok without it as search limited by SearchVector size
15866  check & TotalSearchCounts check
15867  if((abs(EndElement1.HLoc - StartElement1.HLoc) > 120) || (abs(EndElement1.VLoc - StartElement1.VLoc) > 120))
15868  {
15869  if(!Callon) TrainController->StopTTClockMessage(66, "Unable to reach the selected element - too far ahead");
15870  Utilities->CallLogPop(1694);
15871  return false;
15872  }
15873 */
15874 // don't need EveryPrefDir check for NonPreferredRoute
15875 
15876 // check if in an existing route - can't be a 3 or 4 track element so only one TRouteElementPair to be set
15877 // bool InRoute = false;
15879  TAllRoutes::TRouteElementPair RoutePair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(2, TrackElement.HLoc, TrackElement.VLoc, DummyPair);
15880 
15881  if(RoutePair.first > -1)
15882  {
15883  if(RoutePair.second != 0) // not first element in existing route so no good
15884  {
15885  if(!Callon)
15886  {
15887  TrainController->StopTTClockMessage(46, "Can't end a route within or at the end of an existing route");
15888  }
15889  Utilities->CallLogPop(275);
15890  return(false);
15891  }
15892  TPrefDirElement RouteElement = AllRoutes->GetFixedRouteAt(38, RoutePair.first).GetFixedPrefDirElementAt(60, RoutePair.second);
15893 // if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(, RouteElement.Conn[RouteElement.ELinkPos], RouteElement.ELinkPos)))
15894  if((RouteElement.Config[RouteElement.ELinkPos] != End) && (AllRoutes->TrackIsInARoute(12, RouteElement.Conn[RouteElement.ELinkPos],
15895  RouteElement.ConnLinkPos[RouteElement.ELinkPos]))) // amended at v1.3.0 - had omitted ConnLinkPos - see above
15896  // first element in existing route but that route linked to another route (or a non-bridge 2-track element containing a route) so no good
15897  {
15898  if(!Callon)
15899  {
15900  TrainController->StopTTClockMessage(47, "Can't start a route within or at the end of an existing route");
15901  }
15902  Utilities->CallLogPop(276);
15903  return(false);
15904  }
15905  EndElement1 = AllRoutes->GetFixedRouteAt(39, RoutePair.first).GetFixedPrefDirElementAt(61, 0);
15906  EndElement2 = BlankElement; // only need the route element
15907  EndPosition = EndElement1.TrackVectorPosition;
15908  ReqPosRouteID = IDInt(AllRoutes->GetFixedRouteAt(161, RoutePair.first).RouteID);
15909  }
15910 // check if adjacent to start of an existing route and disallow (unless start of existing route is also the start of this route)
15911  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
15912  {
15913  int AdjPosition = AllRoutes->GetFixedRouteAt(40, a).GetFixedPrefDirElementAt(62, 0).TrackVectorPosition;
15914  int AdjLinkPos = AllRoutes->GetFixedRouteAt(219, a).GetFixedPrefDirElementAt(245, 0).ELinkPos; // added at v1.3.1
15915 // if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15916 // && (AdjPosition != StartRoutePosition))
15917  if((EndElement1.Config[EndElement1.XLinkPos] != End) && (EndElement1.Conn[EndElement1.XLinkPos] == AdjPosition)
15918  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15919  (EndElement1.ConnLinkPos[EndElement1.XLinkPos] == AdjLinkPos) && (AdjPosition != StartRoutePosition))
15920  {
15921  if(!Callon)
15922  {
15923  TrainController->StopTTClockMessage(48, "Can't end a route adjacent to the start of an existing route");
15924  }
15925  Utilities->CallLogPop(277);
15926  return(false);
15927  }
15928 // else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End) &&
15929 // (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (AdjPosition != StartRoutePosition))
15930  else if((EndElement2.TrackVectorPosition > -1) && (EndElement2.Config[EndElement2.XLinkPos] != End)
15931  && // changed at v1.3.1 to allow a route end adjacent to an element with a route that doesn't link to the ending route
15932  (EndElement2.Conn[EndElement2.XLinkPos] == AdjPosition) && (EndElement2.ConnLinkPos[EndElement2.XLinkPos] == AdjLinkPos) &&
15933  (AdjPosition != StartRoutePosition))
15934  {
15935  if(!Callon)
15936  {
15937  TrainController->StopTTClockMessage(49, "Can't end a route adjacent to the start of an existing route");
15938  }
15939  Utilities->CallLogPop(278);
15940  return(false);
15941  }
15942 // check if adjacent to end of a route & disallow (unless end of existing route is the start of this route - i.e. extending route by 1 element)
15944  if((EndOfRouteElement.Config[EndOfRouteElement.XLinkPos] != End) && (EndOfRouteElement.Conn[EndOfRouteElement.XLinkPos] == EndPosition) &&
15945  (EndOfRouteElement.TrackVectorPosition != StartRoutePosition))
15946  {
15947  if(!Callon)
15948  {
15949  TrainController->StopTTClockMessage(50, "Can't end a route adjacent to the end of an existing route");
15950  }
15951  Utilities->CallLogPop(279);
15952  return(false);
15953  }
15954  }
15955 
15956 // check for same route as start element
15958  {
15959  if(!Callon)
15960  {
15961  TrainController->StopTTClockMessage(51, "Can't select same route as started in");
15962  }
15963  Utilities->CallLogPop(280);
15964  return(false);
15965  }
15966 // check for a looping route
15967  if((ReqPosRouteID > -1) && (StartSelectionRouteID > -1))
15968  {
15970  {
15971  if(!Callon)
15972  {
15973  TrainController->StopTTClockMessage(70, "Can't create a route that loops back on itself");
15974  }
15975  Utilities->CallLogPop(1845);
15976  return(false);
15977  }
15978  }
15979 // if there's a StartSelectionRouteID StartElement1 will be set to the last entry in the selected route
15980 // so search from this element.
15981 
15982  TTrackElement &TempElement1 = StartElement1; // this needed to avoid a TTrackElement construction ambiguity in later search function
15983 
15984  if(StartSelectionRouteID > -1)
15985  {
15986  if(SearchForNonPreferredRoute(0, TempElement1, StartElement1.XLinkPos, EndPosition, ReqPosRouteID))
15987  {
15989  if(PointsToBeChanged(0))
15990  {
15991  PointsChanged = true;
15992  }
15993  Utilities->CallLogPop(281);
15994  return(true);
15995  }
15996  else
15997  {
15998  if(!Callon)
15999  {
16001  }
16002  Utilities->CallLogPop(282);
16003  return(false);
16004  }
16005  }
16006  else // no starting route, so StartElement1 only has basic values set & is in SearchVector, StartElement2 is blank
16007  // search on the 2 ways out of the element, which has to be a 2-ended element
16008  {
16009 // check if selection adjacent to start element and if so use that
16010  if(SearchVector.at(0).Conn[0] == EndPosition)
16011  {
16012  if(SearchForNonPreferredRoute(1, TempElement1, 0, EndPosition, ReqPosRouteID))
16013  {
16015  if(PointsToBeChanged(1))
16016  {
16017  PointsChanged = true;
16018  }
16019  Utilities->CallLogPop(283);
16020  return(true);
16021  }
16022  else
16023  {
16024  if(!Callon)
16025  {
16027  }
16028  Utilities->CallLogPop(284);
16029  return(false);
16030  }
16031  }
16032  else if(SearchVector.at(0).Conn[1] == EndPosition)
16033  {
16034  if(SearchForNonPreferredRoute(2, TempElement1, 1, EndPosition, ReqPosRouteID))
16035  {
16037  if(PointsToBeChanged(2))
16038  {
16039  PointsChanged = true;
16040  }
16041  Utilities->CallLogPop(285);
16042  return(true);
16043  }
16044  else
16045  {
16046  if(!Callon)
16047  {
16049  }
16050  Utilities->CallLogPop(286);
16051  return(false);
16052  }
16053  }
16054  // now start off in the best direction
16055  int BestPos = Track->FindClosestLinkPosition(1, StartRoutePosition, EndPosition); // can only be 0 or 1
16056 
16057  if(SearchVector.at(0).Config[BestPos] != End)
16058  {
16059  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16060  if(SearchForNonPreferredRoute(3, TempElement1, BestPos, EndPosition, ReqPosRouteID))
16061  {
16063  if(PointsToBeChanged(3))
16064  {
16065  PointsChanged = true;
16066  }
16067  Utilities->CallLogPop(287);
16068  return(true);
16069  }
16070  }
16071  if(SearchVector.at(0).Config[1 - BestPos] != End)
16072  {
16073  TotalSearchCount = 0; // added at v0.4f to give each exit direction a full chance to find required position
16074  if(SearchForNonPreferredRoute(4, TempElement1, (1 - BestPos), EndPosition, ReqPosRouteID))
16075  {
16077  if(PointsToBeChanged(4))
16078  {
16079  PointsChanged = true;
16080  }
16081  Utilities->CallLogPop(288);
16082  return(true);
16083  }
16084  }
16085  }
16086  if(!Callon)
16087  {
16089  }
16090  Utilities->CallLogPop(289);
16091  return(false);
16092 }
16093 
16094 // ---------------------------------------------------------------------------
16095 
16096 bool TOneRoute::SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
16097 /*
16098  This is very similar to the preferred route search, but without the need to ensure all elements are in EveryPrefDir.
16099  Returns true for successful search with SearchVector containing the new route elements. Enter with CurrentTrackElement
16100  stored in SearchVector unless it's in an existing route, & XLinkPos set to the link to search on.
16101  Keep a count of entries in SearchVector during the current function call, so that this number can be
16102  erased for an unproductive branch search.
16103  First check (within the loop) whether XLink leads to an End & return false if so.
16104  Create a NextTrackElement from Current & XLinkPos, and a PrefDirElement (SearchElement) from that, setting as many values as
16105  possible. Check if element is already in searchvector (OK if a bridge & earlier entry on different track, but not OK if
16106  any other type of element), already in an existing route (OK if bridge & diff tracks, or start of an expected route), if
16107  train on element (unless a bridge & train on different track), or if element
16108  fouls an existing diagonal route (except if element is a leading point - these checked later).
16109  Then check if found required element. If so save it & return true.
16110  If not the required element check if buffer or continuation, & if so erase all searchvector
16111  & return false. If OK check if a leading point and if so do up to 2 recursive searches for the 2 exits (trying the 'set' exit first),
16112  checking in each case whether the element fouls an existing diagonal route. If fail on both exits erase searchvector & return false.
16113  If not any of above, store element in SearchVector, increment VectorCount, set the new CurrentTrackElement value from the
16114  SearchElement & the new XLinkPos from SearchElement.XLinkPos, then go back to the while loop for the next step in the search.
16115  When return true have 8 items from CheckCount established, only waiting for EXNumber
16116 */
16117 {
16118  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SearchForNonPreferredRoute," + CurrentTrackElement.LogTrack(14) + "," +
16119  AnsiString(XLinkPos) + "," + AnsiString(RequiredPosition) + "," + AnsiString() + "," + AnsiString(ReqPosRouteID.GetInt()));
16120  int VectorCount = 0;
16121 
16122 // check for a fouled diagonal for first element. Added for v1.3.2
16123  if((CurrentTrackElement.Link[XLinkPos] == 1) || (CurrentTrackElement.Link[XLinkPos] == 3) || (CurrentTrackElement.Link[XLinkPos] == 7) ||
16124  (CurrentTrackElement.Link[XLinkPos] == 9))
16125  {
16126  if(AllRoutes->DiagonalFouledByRouteOrTrain(8, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc, CurrentTrackElement.Link[XLinkPos]))
16127  {
16128  for(int x = 0; x < VectorCount; x++)
16129  {
16130  SearchVector.erase(SearchVector.end() - 1);
16131  }
16132  Utilities->CallLogPop(2044);
16133  return(false);
16134  }
16135  }
16136  while(true)
16137  {
16138  if(Track->IsLCBarrierFlashingAtHV(2, CurrentTrackElement.HLoc, CurrentTrackElement.VLoc)) // can't set a route through a flashing barrier
16139  {
16140  for(int x = 0; x < VectorCount; x++)
16141  {
16142  SearchVector.erase(SearchVector.end() - 1);
16143  }
16144  Utilities->CallLogPop(1927);
16145  return(false);
16146  }
16147  if(CurrentTrackElement.Config[XLinkPos] == End) // buffers or continuation
16148  {
16149  for(int x = 0; x < VectorCount; x++)
16150  {
16151  SearchVector.erase(SearchVector.end() - 1);
16152  }
16153  Utilities->CallLogPop(290);
16154  return(false);
16155  }
16156  int NextPosition = CurrentTrackElement.Conn[XLinkPos];
16157  TTrackElement NextTrackElement = Track->TrackElementAt(93, NextPosition);
16158  TPrefDirElement SearchElement(NextTrackElement);
16159  SearchElement.TrackVectorPosition = NextPosition;
16160  int NextELinkPos = CurrentTrackElement.ConnLinkPos[XLinkPos];
16161  SearchElement.ELinkPos = NextELinkPos;
16162  SearchElement.ELink = SearchElement.Link[SearchElement.ELinkPos];
16163  int NextXLinkPos;
16164  if(SearchElement.ELinkPos == 0)
16165  {
16166  NextXLinkPos = 1;
16167  }
16168  if(SearchElement.ELinkPos == 1)
16169  {
16170  NextXLinkPos = 0;
16171  }
16172  if(SearchElement.ELinkPos == 2)
16173  {
16174  NextXLinkPos = 3;
16175  }
16176  if(SearchElement.ELinkPos == 3)
16177  {
16178  NextXLinkPos = 2;
16179  }
16180  if((SearchElement.TrackType != Points) || (SearchElement.Config[SearchElement.ELinkPos] != Lead))
16181  {
16182  SearchElement.XLink = SearchElement.Link[NextXLinkPos];
16183  // but may be buffers, continuation or gap
16184  SearchElement.XLinkPos = NextXLinkPos;
16185  }
16186 // Now have SpeedTag, HLoc, VLoc, TrackVectorPosition, ELink, ELinkPos, and for non-points XLink & XLinkPos
16187 // can't set XLink or XLinkPos yet if the element is a leading point.
16188 
16189 // check if reached an earlier position on search PrefDir (was OK in SearchForPrefDir if entry values different, but not OK for a route)
16190  for(unsigned int x = 0; x < SearchVector.size(); x++)
16191  {
16192  if(SearchElement.TrackVectorPosition == SearchVector.at(x).TrackVectorPosition)
16193  {
16194  if((SearchElement.TrackType != Bridge) || ((SearchElement.TrackType == Bridge) && (SearchElement.ELink == SearchVector.at(x).ELink)))
16195  // OK if it's a bridge & routes on different tracks
16196  {
16197  for(int x = 0; x < VectorCount; x++)
16198  {
16199  SearchVector.erase(SearchVector.end() - 1);
16200  }
16201  Utilities->CallLogPop(291);
16202  return(false);
16203  }
16204  }
16205  }
16206 
16207 // check if element in an existing route (OK if bridge & diff tracks, or start of an expected route)
16208  TAllRoutes::TRouteElementPair SecondPair;
16210  Track->TrackElementAt(94, SearchElement.TrackVectorPosition).HLoc, Track->TrackElementAt(95, SearchElement.TrackVectorPosition).VLoc, SecondPair);
16211  if(RoutePair.first > -1)
16212  {
16213  // OK if it's a bridge & routes on different tracks (hard to see how can reach a bridge before another element in route as can't start on a bridge, but leave check in anyway)
16214  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(43, RoutePair.first).GetFixedPrefDirElementAt(64,
16215  RoutePair.second).ELinkPos)))
16216  {
16217  // still OK if start of an expected route
16218  if((ReqPosRouteID == IDInt(-1)) || ((int)RoutePair.first != AllRoutes->GetRouteVectorNumber(4, ReqPosRouteID)) || (RoutePair.second != 0))
16219  {
16220  for(int x = 0; x < VectorCount; x++)
16221  {
16222  SearchVector.erase(SearchVector.end() - 1);
16223  }
16224  Utilities->CallLogPop(292);
16225  return(false); // only allow for start of an expected route
16226  }
16227  }
16228  }
16229  if(SecondPair.first > -1) // if reach here & secondpair present then must fail as can't escape both existing routes, but leave check as before anyway
16230  {
16231  // OK if it's a bridge & routes on different tracks
16232  if(!((SearchElement.TrackType == Bridge) && (SearchElement.ELinkPos != AllRoutes->GetFixedRouteAt(44, SecondPair.first).GetFixedPrefDirElementAt(65,
16233  SecondPair.second).ELinkPos)))
16234  {
16235  // still OK if start of an expected route
16236  if((ReqPosRouteID == IDInt(-1)) || ((int)SecondPair.first != AllRoutes->GetRouteVectorNumber(5, ReqPosRouteID)) || (SecondPair.second != 0))
16237  {
16238  for(int x = 0; x < VectorCount; x++)
16239  {
16240  SearchVector.erase(SearchVector.end() - 1);
16241  }
16242  Utilities->CallLogPop(293);
16243  return(false); // only allow for start of an expected route
16244  }
16245  }
16246  }
16247 // check if a train on element, unless a bridge & train on different track
16248 // OK of same train as start element - no, drop this
16249 // if(SearchElement.TrainIDOnElement != StartSelectionTrainID)
16250  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType != Bridge))
16251  {
16252  for(int x = 0; x < VectorCount; x++)
16253  {
16254  SearchVector.erase(SearchVector.end() - 1);
16255  }
16256  Utilities->CallLogPop(294);
16257  return(false);
16258  }
16259  if((SearchElement.TrainIDOnElement > -1) && (SearchElement.TrackType == Bridge))
16260  {
16261  if((SearchElement.ELinkPos < 2) && (SearchElement.TrainIDOnBridgeTrackPos01 > -1))
16262  {
16263  for(int x = 0; x < VectorCount; x++)
16264  {
16265  SearchVector.erase(SearchVector.end() - 1);
16266  }
16267  Utilities->CallLogPop(295);
16268  return(false);
16269  }
16270  else if((SearchElement.ELinkPos > 1) && (SearchElement.TrainIDOnBridgeTrackPos23 > -1))
16271  {
16272  for(int x = 0; x < VectorCount; x++)
16273  {
16274  SearchVector.erase(SearchVector.end() - 1);
16275  }
16276  Utilities->CallLogPop(296);
16277  return(false);
16278  }
16279  }
16280 // check for a fouled diagonal (if not leading point - leading point XLink == -1)
16281  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16282  {
16283  if(AllRoutes->DiagonalFouledByRouteOrTrain(3, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16284  {
16285  for(int x = 0; x < VectorCount; x++)
16286  {
16287  SearchVector.erase(SearchVector.end() - 1);
16288  }
16289  Utilities->CallLogPop(297);
16290  return(false);
16291  }
16292  }
16293 // check if exceeds the search H & V limits - drop in favour of limiting TotalSearchCount
16294 // if((SearchElement.HLoc > SearchLimitHighH) || (SearchElement.HLoc < SearchLimitLowH) ||
16295 // (SearchElement.VLoc > SearchLimitHighV) ||(SearchElement.VLoc < SearchLimitLowV))
16297  {
16298  for(int x = 0; x < VectorCount; x++)
16299  {
16300  SearchVector.erase(SearchVector.end() - 1);
16301  }
16302  Utilities->CallLogPop(1689);
16303  return(false);
16304  }
16305 // check if found it
16306  if(SearchElement.TrackVectorPosition == RequiredPosition)
16307  {
16308  if(SearchElement.TrackType == Points) // can only happen for platform element in CallingOnAllowed function
16309  {
16310  if((SearchElement.ELinkPos == 1) || (SearchElement.ELinkPos == 3))
16311  {
16312  SearchElement.XLinkPos = 0; // select the straight track (for the platform)
16313  }
16314  else
16315  {
16316  SearchElement.XLinkPos = 1;
16317  }
16318 // SearchElement.XLink = SearchElement.Link[XLinkPos]; WRONG!! NajamUddin found this error 17/01/11, XLinkPos is the function input parameter, should be SearchElement.XLinkPos
16319  SearchElement.XLink = SearchElement.Link[SearchElement.XLinkPos]; // corrected for v0.6a
16320  }
16321  SearchVector.push_back(SearchElement);
16322  VectorCount++; // not really needed but include for tidyness
16323  TotalSearchCount++;
16324  Utilities->CallLogPop(298);
16325  return(true);
16326  }
16327 // Not the required element - check if a buffer or continuation
16328  if((SearchElement.TrackType == Buffers) || (SearchElement.TrackType == Continuation))
16329  {
16330  for(int x = 0; x < VectorCount; x++)
16331  {
16332  SearchVector.erase(SearchVector.end() - 1);
16333  }
16334  Utilities->CallLogPop(299);
16335  return(false);
16336  }
16337 // check if SearchVector exceeds a size of 150
16338  if(SearchVector.size() > 150)
16339  {
16340  for(int x = 0; x < VectorCount; x++)
16341  {
16342  SearchVector.erase(SearchVector.end() - 1);
16343  }
16344  Utilities->CallLogPop(1421);
16345  return(false);
16346  }
16347 // check if reached a leading point
16348  if((SearchElement.TrackType == Points) && (SearchElement.Config[SearchElement.ELinkPos] == Lead))
16349  {
16350 // XLink set to points 'set' position - Attribute == 0, SearchPos1 = 1 & SearchPos2 = 3; Attribute == 1, SearchPos1 = 3 & SearchPos2 = 1;
16351  int SearchPos1 = SearchElement.Attribute + 1;
16352  int SearchPos2;
16353  if(SearchPos1 == 2)
16354  {
16355  SearchPos1++;
16356  }
16357  if(SearchPos1 == 1)
16358  {
16359  SearchPos2 = 3;
16360  }
16361  else
16362  {
16363  SearchPos2 = 1;
16364  }
16365 // push element with XLink set to position [SearchPos1]
16366  SearchElement.XLink = SearchElement.Link[SearchPos1];
16367  SearchElement.XLinkPos = SearchPos1;
16368 // check for a fouled diagonal for leading point for XLinkPos == SearchPos1)
16369  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16370  {
16371  if(AllRoutes->DiagonalFouledByRouteOrTrain(4, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16372  {
16373  for(int x = 0; x < VectorCount; x++)
16374  {
16375  SearchVector.erase(SearchVector.end() - 1);
16376  }
16377  Utilities->CallLogPop(300);
16378  return(false);
16379  }
16380  }
16381  SearchVector.push_back(SearchElement);
16382  VectorCount++;
16383  TotalSearchCount++;
16384 // recursive search at XLinkPos of SearchPos1 (i.e. 'set' trailing exit)
16385 // Note that NextTrackElement is the TTrackElement that the TPrefDirElement SearchElement is constructed from. Can't use SearchElement in the
16386 // recursive search as has to be a TTrackElement for non-preferred route searches
16387  if(SearchForNonPreferredRoute(6, NextTrackElement, SearchPos1, RequiredPosition, ReqPosRouteID))
16388  {
16389  Utilities->CallLogPop(301);
16390  return(true);
16391  }
16392  else
16393  {
16394 // remove leading point with XLinkPos [SearchPos1]
16395  SearchVector.erase(SearchVector.end() - 1);
16396  VectorCount--;
16397 // push element with XLink set to position [SearchPos2]
16398  SearchElement.XLink = SearchElement.Link[SearchPos2];
16399  SearchElement.XLinkPos = SearchPos2;
16400 // check for a fouled diagonal for leading point for XLinkPos == SearchPos2)
16401  if((SearchElement.XLink == 1) || (SearchElement.XLink == 3) || (SearchElement.XLink == 7) || (SearchElement.XLink == 9))
16402  {
16403  if(AllRoutes->DiagonalFouledByRouteOrTrain(5, SearchElement.HLoc, SearchElement.VLoc, SearchElement.XLink))
16404  {
16405  for(int x = 0; x < VectorCount; x++)
16406  {
16407  SearchVector.erase(SearchVector.end() - 1);
16408  }
16409  Utilities->CallLogPop(302);
16410  return(false);
16411  }
16412  }
16413  SearchVector.push_back(SearchElement);
16414  VectorCount++;
16415  TotalSearchCount++;
16416 // recursive search at XLinkPos of SearchPos2 (i.e. 'unset' trailing exit)
16417  if(SearchForNonPreferredRoute(7, NextTrackElement, SearchPos2, RequiredPosition, ReqPosRouteID))
16418  {
16419  Utilities->CallLogPop(303);
16420  return(true);
16421  }
16422  else
16423  {
16424  for(int x = 0; x < VectorCount; x++)
16425  {
16426  SearchVector.erase(SearchVector.end() - 1);
16427  }
16428  Utilities->CallLogPop(304);
16429  return(false);
16430  }
16431  }
16432  } // if leading point
16433 
16434 // here if ordinary element, push it, inc VectorCount & update CurrentTrackElement
16435 // ready for next element on route
16436  SearchVector.push_back(SearchElement);
16437  VectorCount++;
16438  TotalSearchCount++;
16439  CurrentTrackElement = SearchElement;
16440  XLinkPos = SearchElement.XLinkPos; // wasn't a leading point so XLinkPos defined
16441  } // while(true)
16442 }
16443 
16444 // ---------------------------------------------------------------------------
16445 
16447 
16448 /*
16449  This function is developed from ConvertPrefDirSearchVector, to deal with search elements not
16450  having all values set (since not necessarily on PrefDirs).
16451  Enter with SearchVector established, return if empty. The first element may not have its ELink & XLink etc set
16452  (if it was the start), so these are checked first and set if necessary. All elements now have
16453  all but EXNumber set, so the CheckCount is set to 8 to cover all but EXNumber, and that is then set
16454  for all elements (unless validity check fails) and CheckCount incremented. Finally SetRouteSearchVectorGraphics() is called
16455  to set the route colour and direction graphics.
16456 */
16457 
16458 {
16459  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRemainingSearchVectorValues");
16460  if(SearchVector.size() == 0)
16461  {
16462  throw Exception("Error, SearchVector empty");
16463  }
16464 // first SearchElement may have ELink & XLink not set if entered in GetStart.... i.e if it wasn't already in a route
16465 // hence need to examine and update it if necessary
16466  TPrefDirElement SecondElement;
16467 
16468  if(SearchVector.size() > 1) // if search vector only a single element then first element must have been in a route, and in this case
16469  // all data members will have been set in SearchForNonPreferredRoute except for EXNumber.
16470  // need above check or SecondElement will fail
16471  {
16472  SecondElement = SearchVector.at(1);
16473  // SearchVector.at(0) ELink & XLink not set if was first element in route; XLink also not set if was a leading point though can't be for a route
16474  for(int x = 0; x < 4; x++)
16475  {
16476  if(SearchVector.at(0).Conn[x] == SecondElement.TrackVectorPosition)
16477  {
16478  if(SearchVector.at(0).XLink == -1) // i.e. not set
16479  {
16480  SearchVector.at(0).XLink = SearchVector.at(0).Link[x];
16481  SearchVector.at(0).XLinkPos = x;
16482  }
16483  int ELinkPos;
16484  if(SearchVector.at(0).XLinkPos == 0)
16485  {
16486  ELinkPos = 1; // use actual value rather than 'x' as may be a gap with both ends
16487  }
16488  // linked to 1st searchvector element, & if XLink was set then x may not correspond
16489  if(SearchVector.at(0).XLinkPos == 1)
16490  {
16491  ELinkPos = 0;
16492  }
16493  if(SearchVector.at(0).XLinkPos == 2)
16494  {
16495  ELinkPos = 3;
16496  }
16497  if(SearchVector.at(0).XLinkPos == 3)
16498  {
16499  ELinkPos = 2;
16500  }
16501  if(SearchVector.at(0).ELink == -1) // because was start element, & can't be points, but could be a gap
16502  {
16503  SearchVector.at(0).ELink = SearchVector.at(0).Link[ELinkPos];
16504  SearchVector.at(0).ELinkPos = ELinkPos;
16505  }
16506  break; // no point going any further
16507  }
16508  }
16509  }
16510  for(unsigned int x = 0; x < SearchVector.size(); x++)
16511  {
16512  SearchVector.at(x).CheckCount = 8; // to account for all but EXNumber
16513 // set EXNumber
16514  if(!(SearchVector.at(x).EntryExitNumber()))
16515  {
16516  throw Exception("Error in EntryExitNumber 3");
16517  }
16518  SearchVector.at(x).CheckCount++;
16519 // all values now incorporated
16520  }
16521 
16522  SetRouteSearchVectorGraphics(5, false, false); // change graphic colour to the route colour
16523 // This function is only called here for nonsignals routes, so AutoSigsFlag & PrefDirRoute both false
16524 // PrefDir is validated in ConvertAndAddNonPreferredRouteSearchVector
16525  Utilities->CallLogPop(305);
16526 }
16527 
16528 // ---------------------------------------------------------------------------
16529 
16531 
16532 /*
16533  This function is very similar to ConvertAndAddPreferredRouteSearchVector except that the route in SearchVector can't be an
16534  AutoSigsRoute.
16535  Action varies depending on whether it is a completely new route, or an extension of an existing route at the
16536  beginning or the end.
16537  Ignore if SearchVector empty, and check that all the new elements in SearchVector are valid.
16538  Check if route end selection is in an existing route (ReqPosRouteID > -1), if so and existing route is non-autosigs
16539  add its elements to the SearchVector then delete the route, decrementing StartSelectionRouteNumber if the RequPosRouteNumber was
16540  less than StartSelectionRouteID. If existing route is AutoSigs then the final search element is dropped from the SearchVector,
16541  since the new route will end adjacent to the AutoSigs route, and the existing route is left as it is.
16542  Note that a single route cannot contain both AutoSig & non-AutoSig elements, each route of AutoSig elements
16543  has its own identity. A single route can however have a mixture of Unrestricted and PreferredRoute elements
16544 
16545  Check if StartSelectionRouteID set (extending an existing route) and if so and if existing route non-autosig, then add the new route
16546  to the existing route (start element not stored in searchvector), call SetRoutePoints & SetRouteSignals for the extended route and return.
16547  If the existing route is autosig, then leave the existing route as it is and continue as for routes that aren't linked to an existing
16548  route at the start.
16549 
16550  Check the validity of the route in SearchVector, and create a new route using StoreOneRoute. Finally call SetRoutePoints & SetRouteSignals
16551  for the new route and return.
16552 */
16553 
16554 {
16555  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ConvertAndAddNonPreferredRouteSearchVector," +
16556  AnsiString(ReqPosRouteID.GetInt()));
16557  if(SearchVector.size() < 1)
16558  {
16559  Utilities->CallLogPop(306);
16560  return;
16561  }
16562  PrefDirVector = SearchVector; // this copy is to validate the vector up to this point,
16563  if(!ValidatePrefDir(6))
16564  {
16565  Utilities->CallLogPop(307);
16566  return;
16567  }
16568  TAllRoutes::TLockedRouteClass LockedRouteObject;
16569 
16571  unsigned int TruncatePrefDirPosition = 0;
16572 
16573  if(ReqPosRouteID > -1) // Note that ReqPosRouteID != StartSelectionRouteID as would have failed in GetNextRouteElement
16574 /* if have ReqPosRouteID:
16575  if existing route non-autosig, then add the old route to the SearchVector then delete the old route
16576  if existing route autosig, drop the final search element in the new route, leave the existing route as it is,
16577  then enter the new route into the AllRoutesVector
16578 */
16579  {
16581  {
16582  for(unsigned int x = 1; x < AllRoutes->GetFixedRouteAtIDNumber(46, ReqPosRouteID).PrefDirSize();
16583  x++) // start at 1 as first element already in SearchVector
16584  {
16586  }
16587  // note that route numbers in map adjusted when ReqPos route cleared
16589  // create a new locked route object (apart from RouteNumber) if required, for use later (LockedRouteFoundDuringRouteBuilding
16590  // set during ClearRouteDuringRouteBuildingAt)
16592  {
16595  LockedRouteObject.LastXLinkPos = AllRoutes->LockedRouteLastXLinkPos;
16596  LockedRouteObject.LockStartTime = AllRoutes->LockedRouteLockStartTime;
16597  }
16598  }
16600  {
16601  SearchVector.pop_back();
16602  }
16603  }
16604  if(StartSelectionRouteID > -1)
16605 /* if have StartSelectionRouteID:
16606  if existing route non-autosig, then add the new route to the existing route (start element not stored in searchvector)
16607  if existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16608 */
16609  {
16611  // need to test because may have been removed by a train moving in the wrong direction between first and last route selections - added at v1.3.1
16612  {
16614  {
16615  int RouteNumber = AllRoutes->GetRouteVectorNumber(1, StartSelectionRouteID);
16616  for(unsigned int x = 0; x < SearchVector.size(); x++)
16617  {
16619  RouteNumber, GetFixedSearchElementAt(7, x));
16620  // find & store locked route truncate position in PrefDirVector for later use
16622  {
16623  if(GetFixedSearchElementAt(16, x).TrackVectorPosition == int(AllRoutes->LockedRouteTruncateTrackVectorPosition))
16624  {
16625  TruncatePrefDirPosition = AllRoutes->GetFixedRouteAt(176, RouteNumber).PrefDirSize() - 1;
16626  }
16627  }
16628  }
16630  {
16631  throw Exception("Failed to validate extended route for nonpreferred route");
16632  }
16635  AllRoutes->GetModifiableRouteAtIDNumber(9, StartSelectionRouteID).SetLCChangeValues(2, false); // PrefDirRoute is false
16636  // now add the reinstated locked route if required and set signals accordingly
16637  // shouldn't ever need to access this as the train that has caused the locked route will be ahead of the route to be added,
16638  // and it will have removed the route elements that it is standing on, but include in case there's some obscure condition
16639  // that I haven't thought of
16641  {
16642  LockedRouteObject.RouteNumber = RouteNumber;
16643  AllRoutes->LockedRouteVector.push_back(LockedRouteObject);
16644  // now reset the signals for the locked route
16645  AllRoutes->SetAllRearwardsSignals(12, 0, RouteNumber, TruncatePrefDirPosition);
16646  for(int c = AllRoutes->GetFixedRouteAt(177, RouteNumber).PrefDirSize() - 1; c >= (int)TruncatePrefDirPosition;
16647  c--) // must use int for >= test to succeed when TruncatePrefDirPosition == 0
16648  {
16649  // return all signals to red in route section to be truncated
16650  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(178, RouteNumber).PrefDirVector.at(c);
16651  TTrackElement & TrackElement = Track->TrackElementAt(813, PrefDirElement.TrackVectorPosition);
16652  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
16653  {
16654  TrackElement.Attribute = 0;
16655  Track->PlotSignal(11, TrackElement, Display);
16656  Display->PlotOutput(115, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
16657  Display->PlotOutput(116, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
16658  }
16659  }
16660  }
16661  AllRoutes->CheckMapAndRoutes(3); // test
16662  Utilities->CallLogPop(308);
16663  return;
16664  }
16665  }
16666  else
16667  {
16669  }
16670 // if new route non-autosig and existing route autosig, leave the existing route as it is, and just enter the new route into the AllRoutesVector
16671 // hence nothing to do here
16672  }
16673  PrefDirVector = SearchVector; // copy again prior to storing as a route as SearchVector may have been extended
16674  if(!ValidatePrefDir(8)) // validate PrefDir for all new route elements
16675  {
16676  throw Exception("Failed to validate single route for nonpreferred route");
16677  }
16678  AllRoutes->StoreOneRoute(2, this);
16679  AllRoutes->GetModifiableRouteAt(6, AllRoutes->AllRoutesSize() - 1).SetRoutePoints(3); // new addition
16680  AllRoutes->GetModifiableRouteAt(17, AllRoutes->AllRoutesSize() - 1).SetRouteSignals(7); // new addition
16681  AllRoutes->GetModifiableRouteAt(19, AllRoutes->AllRoutesSize() - 1).SetLCChangeValues(3, false); // ConsecSignalsRoute is false
16682  AllRoutes->CheckMapAndRoutes(4); // test
16683  Utilities->CallLogPop(309);
16684 }
16685 
16686 // ---------------------------------------------------------------------------
16687 
16688 void TOneRoute::SetRoutePoints(int Caller) const
16689 /*
16690  Examine each set of points in the route to see if entry or exit is via the straight or diverging trailing
16691  link, and set the attribute accordingly (don't need to worry about linked routes, points in those will have been set
16692  when they were created.
16693 */
16694 {
16695  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRoutePoints");
16696  if(!PrefDirVector.empty())
16697  {
16698  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16699  {
16700  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 1) || (PrefDirPtr->XLinkPos == 1))) // 1=straight trailing
16701  {
16702  Track->TrackElementAt(96, PrefDirPtr->TrackVectorPosition).Attribute = 0; // 0=straight
16703  Track->PlotPoints(3, Track->TrackElementAt(97, PrefDirPtr->TrackVectorPosition), Display, false);
16704  }
16705  if((PrefDirPtr->TrackType == Points) && ((PrefDirPtr->ELinkPos == 3) || (PrefDirPtr->XLinkPos == 3))) // 3=diverging trailing
16706  {
16707  Track->TrackElementAt(98, PrefDirPtr->TrackVectorPosition).Attribute = 1; // 1=diverging
16708  Track->PlotPoints(4, Track->TrackElementAt(99, PrefDirPtr->TrackVectorPosition), Display, false);
16709  }
16710  }
16711  }
16712  Utilities->CallLogPop(327);
16713 }
16714 
16715 // ---------------------------------------------------------------------------
16716 
16717 void TOneRoute::SetRouteSignals(int Caller) const
16718 /* Used for new train additions in AddTrain and in route setting
16719  Set the signals as follows:-
16720  First check whether there is a linked forward route, and if so use FindForwardTargetSignalAttribute to work along it from the start
16721  until find a train (return Attribute = 0 & NextForwardLinkedRouteNumber = -1), a buffer (return Attribute = 1 &
16722  NextForwardLinkedRouteNumber = -1), a continuation (return Attribute = 3 & NextForwardLinkedRouteNumber = -1) or a forward-facing
16723  signal. If find a signal its attribute value + 1 up to a maximum value of 3 is returned & NextForwardLinkedRouteNumber = -1.
16724  The above Attribute values represent the 'target' attribute, from which all rearwards signals in turn in the new route are set,
16725  the first using the returned attribute value and subsequent ones incrementing the Attribute up to a maximum of 3. All the foregoing
16726  return true, as does finding none of the above and no onward linked forward route (NextForwardLinkedRouteNumber = -1). If none
16727  of the foregoing are found but there is a further forward linked forward route then the function returns false with
16728  NextForwardLinkedRouteNumber = the next forward linked route number, to allow that to be examined similarly, and Attribute = 0.
16729 
16730  When the target Attribute is found (will be 0 if no forward linked route), then SetAllRearwardsSignals is used to work back from
16731  the end of the route setting each forward-facing signal one step nearer green as described above, until either reach the end of all
16732  linked rearwards routes or find a train. If find a train in the current route then signals behind it (and behind any other trains
16733  in the current route) are set appropriately (including in linked rear routes), but if find a train in a linked rear route then no
16734  further signals are set. If there is no forward linked route and the front end of the current route is a buffer then
16735  SetAllRearwardsSignals (in its call to SetRearwardsSignalsReturnFalseForTrain) treats it as a red signal, and if a continuation,
16736  as a green signal.
16737 */
16738 {
16739  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSignals");
16740  if(!PrefDirVector.empty())
16741  {
16742  // get target Attribute value, check first if there is a forward linked route
16743  TPrefDirElement LastElement = GetFixedPrefDirElementAt(185, PrefDirSize() - 1);
16744  TPrefDirElement FirstElement = GetFixedPrefDirElementAt(186, 0);
16745  int ForwardLinkedRouteNumber, Attribute = 0;
16746  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16747  // Note that LastElement can't be points but can be linked to points
16748  {
16749  if(AllRoutes->GetRouteTypeAndNumber(16, LastElement.Conn[LastElement.XLinkPos], LastElement.ConnLinkPos[LastElement.XLinkPos],
16750  ForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16751  {
16752  if(ForwardLinkedRouteNumber > -1)
16753  {
16754  int NextForwardLinkedRouteNumber = -1;
16755  while(!(AllRoutes->GetFixedRouteAt(171, ForwardLinkedRouteNumber).FindForwardTargetSignalAttribute(1, NextForwardLinkedRouteNumber,
16756  Attribute)))
16757  {
16758  ForwardLinkedRouteNumber = NextForwardLinkedRouteNumber;
16759  }
16760  // if find a train before a signal then Attribute = 0, else if find end of route is a buffer then Attribute = 1, or a continuation then
16761  // Attribute = 3, else if find signal then Attribute = (signal attribute + 1) up to a max value of 3. All these return true, if find a
16762  // forward linked route then the routenumber is set in NextForwardLinkedRouteNumber, Attribute = 0 & returns false.
16763  }
16764  }
16765  }
16766  int RouteNumber;
16767  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(15, GetFixedPrefDirElementAt(187, 0).TrackVectorPosition,
16768  GetFixedPrefDirElementAt(193, 0).XLinkPos, RouteNumber);
16769  if(RouteType != TAllRoutes::NoRoute)
16770  // it will be, above only used to get RouteNumber, can choose any element in the route so use GetFixedPrefDirElementAt
16771  {
16772  AllRoutes->SetAllRearwardsSignals(8, Attribute, RouteNumber, PrefDirSize() - 1);
16773  }
16774  }
16775  Utilities->CallLogPop(1720);
16776 }
16777 
16778 // ---------------------------------------------------------------------------
16779 
16780 bool TOneRoute::PointsToBeChanged(int Caller) const
16781 {
16782  // true if at any point in SearchVector points have to be changed
16783  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",PointsToBeChanged");
16784  if(!SearchVector.empty())
16785  {
16786  for(TPrefDirVectorConstIterator SearchPtr = SearchVector.begin(); SearchPtr != SearchVector.end(); SearchPtr++)
16787  {
16788  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 1) || (SearchPtr->XLinkPos == 1))) // 1=straight trailing
16789  {
16790  if(Track->TrackElementAt(752, SearchPtr->TrackVectorPosition).Attribute != 0) // 0=straight or LH
16791  {
16792  Utilities->CallLogPop(1717);
16793  return(true);
16794  }
16795  }
16796  if((SearchPtr->TrackType == Points) && ((SearchPtr->ELinkPos == 3) || (SearchPtr->XLinkPos == 3))) // 3=diverging trailing
16797  {
16798  if(Track->TrackElementAt(753, SearchPtr->TrackVectorPosition).Attribute != 1) // 1=diverging or RH
16799  {
16800  Utilities->CallLogPop(1718);
16801  return(true);
16802  }
16803  }
16804  }
16805  }
16806  Utilities->CallLogPop(1719);
16807  return(false);
16808 }
16809 
16810 // ---------------------------------------------------------------------------
16811 
16812 bool TOneRoute::FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
16813 /*
16814  Works forward through the route until finds:-
16815  (a) a train - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16816  (b) end of route at buffers - Attribute = 1, NextForwardLinkedRouteNumber = -1 & returns true;
16817  (c) end of route at continuation - Attribute = 3, NextForwardLinkedRouteNumber = -1 & returns true;
16818  (d) level crossing with barriers not down - Attribute = 0, NextForwardLinkedRouteNumber = -1 & returns true;
16819  (e) forward-facing signal - Attribute = 1 + signal attribute (max value of 3), NextForwardLinkedRouteNumber = -1 & returns true;
16820  (f) end of route not at any of foregoing and with no linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = -1 &
16821  returns true;
16822  (g) linked forward route - Attribute = 0, NextForwardLinkedRouteNumber = the routenumber of the forward route & returns false.
16823 */
16824 {
16825  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindForwardTargetSignalAttribute");
16826  Attribute = 0;
16827  NextForwardLinkedRouteNumber = -1;
16828  for(unsigned int x = 0; x < PrefDirSize(); x++)
16829  {
16830  int TrainID = Track->TrackElementAt(100, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnElement;
16831  if(PrefDirVector.at(x).TrackType == Bridge)
16832  {
16833  if(PrefDirVector.at(x).XLinkPos < 2)
16834  {
16835  TrainID = Track->TrackElementAt(101, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16836  }
16837  else
16838  {
16839  TrainID = Track->TrackElementAt(102, PrefDirVector.at(x).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16840  }
16841  }
16842  if(TrainID != -1)
16843  {
16844  Utilities->CallLogPop(328);
16845  return(true);
16846  }
16847  if(PrefDirVector.at(x).TrackType == Buffers)
16848  {
16849  Attribute = 1;
16850  Utilities->CallLogPop(329);
16851  return(true);
16852  }
16853  if(PrefDirVector.at(x).TrackType == Continuation)
16854  {
16855  Attribute = 3;
16856  Utilities->CallLogPop(330);
16857  return(true);
16858  }
16859  if(Track->IsLCAtHV(42, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16860  {
16861  if(!Track->IsLCBarrierDownAtHV(3, PrefDirVector.at(x).HLoc, PrefDirVector.at(x).VLoc))
16862  {
16863  Attribute = 0;
16864  Utilities->CallLogPop(1950);
16865  return(true);
16866  }
16867  }
16868  if(PrefDirVector.at(x).Config[PrefDirVector.at(x).XLinkPos] == Signal)
16869  {
16870  Attribute = Track->TrackElementAt(103, PrefDirVector.at(x).TrackVectorPosition).Attribute + 1;
16871  if(Attribute > 3)
16872  {
16873  Attribute = 3;
16874  }
16875  Utilities->CallLogPop(331);
16876  return(true);
16877  }
16878  if(x == PrefDirSize() - 1)
16879  {
16880  TPrefDirElement LastElement = PrefDirVector.at(x);
16881  if(LastElement.Conn[LastElement.XLinkPos] > -1)
16882  {
16883  if(AllRoutes->GetRouteTypeAndNumber(2, LastElement.Conn[LastElement.XLinkPos],
16884  Track->GetNonPointsOppositeLinkPos(LastElement.ConnLinkPos[LastElement.XLinkPos]), NextForwardLinkedRouteNumber) != TAllRoutes::NoRoute)
16885  {
16886  Attribute = 0;
16887  Utilities->CallLogPop(332);
16888  return(false);
16889  }
16890  }
16891  }
16892  }
16893  Utilities->CallLogPop(333);
16894  return(true);
16895 }
16896 
16897 // ---------------------------------------------------------------------------
16898 
16899 bool TOneRoute::SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
16900 /*
16901  This function is only called by TAllRoutes::SetAllRearwardsSignals.
16902 
16903  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
16904  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
16905  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
16906  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
16907  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
16908  a route.
16909 
16910  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
16911  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
16912  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
16913  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working
16914  backwards for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
16915  reference. If no train is found before the beginning of the route is reached the function returns true
16916 
16917  In setting signals skip the first position if it's a signal and if truncating - otherwise the truncated signal counts as the first red
16918  and the next rearwards signal becomes yellow, although it's the first in the route
16919 */
16920 {
16921  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRearwardsSignalsReturnFalseForTrain," + AnsiString(Attribute) + "," +
16922  AnsiString(PrefDirVectorStartPosition));
16923  Graphics::TBitmap *EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default values
16924  Graphics::TBitmap *EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd;
16925 // if no train between end of route and PrefDirVectorStartPosition, route not in ContinuationAutoSigVector
16926 // & not truncating a route, then Attribute can be modified if end is buffers or continuation
16927  bool SkipContinuationAndBufferAttributeChange = false;
16928 
16929  if(!PrefDirVector.empty())
16930  {
16931  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr < PrefDirVector.end(); PrefDirPtr++)
16932  {
16933  int TrainID = Track->TrackElementAt(104, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16934  if(PrefDirPtr->TrackType == Bridge)
16935  {
16936  if(PrefDirPtr->XLinkPos < 2)
16937  {
16938  TrainID = Track->TrackElementAt(105, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16939  }
16940  else
16941  {
16942  TrainID = Track->TrackElementAt(106, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16943  }
16944  }
16945  if(TrainID != -1)
16946  {
16947  SkipContinuationAndBufferAttributeChange = true;
16948  break;
16949  }
16950  }
16951 
16954  {
16955  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.begin(); AutoSigVectorIT < TrainController->ContinuationAutoSigVector.end();
16956  AutoSigVectorIT++)
16957  {
16958  if(!AllRoutes->AllRoutesVector.empty())
16959  {
16960  if((&AllRoutes->AllRoutesVector.front() + AutoSigVectorIT->RouteNumber) == this)
16961  {
16962  SkipContinuationAndBufferAttributeChange = true;
16963  break;
16964  }
16965  }
16966  }
16967  }
16969  {
16970  SkipContinuationAndBufferAttributeChange = true;
16971  }
16972  if(!SkipContinuationAndBufferAttributeChange)
16973  {
16974  if(PrefDirVector.back().TrackType == Buffers)
16975  {
16976  Attribute = 1; // treat buffer as red signal
16977  }
16978  if(PrefDirVector.back().TrackType == Continuation)
16979  {
16980  Attribute = 3; // treat continuation as a green signal
16981  }
16982  }
16983  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.begin() + PrefDirVectorStartPosition); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
16984  {
16985  int TrainID = Track->TrackElementAt(107, PrefDirPtr->TrackVectorPosition).TrainIDOnElement;
16986  if(PrefDirPtr->TrackType == Bridge)
16987  {
16988  if(PrefDirPtr->XLinkPos < 2)
16989  {
16990  TrainID = Track->TrackElementAt(108, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos01;
16991  }
16992  else
16993  {
16994  TrainID = Track->TrackElementAt(109, PrefDirPtr->TrackVectorPosition).TrainIDOnBridgeTrackPos23;
16995  }
16996  }
16997  if(TrainID != -1)
16998  {
16999  Utilities->CallLogPop(334);
17000  return(false);
17001  }
17002  // if find an LC that is closed to trains (or flashing - may be extending an earlier route with flashing LCs) then reset
17003  // the attribute to 0 so first signal behind the LC is red
17004  if(Track->IsLCAtHV(20, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17005  {
17006  if(!Track->IsLCBarrierDownAtHV(1, PrefDirPtr->HLoc, PrefDirPtr->VLoc))
17007  {
17008  Attribute = 0;
17009  }
17010  }
17011 // now set signals, but skip the first position if it's a signal on an unrestricted route and truncating - otherwise the truncated signal
17012 // counts as the first red and the next rearwards signal becomes yellow, although it's the first in the route
17013  if(PrefDirPtr->Config[PrefDirPtr->XLinkPos] == Signal)
17014  {
17015  if((!AllRoutes->RouteTruncateFlag) || (PrefDirPtr != (PrefDirVector.begin() + PrefDirVectorStartPosition)) || PrefDirPtr->AutoSignals ||
17016  PrefDirPtr->PrefDirRoute)
17017  {
17018 //new section at v2.9.2 to check for pref dir element in a locked route, and if so set Attribute to 0 (red). When emerge from locked route Attribute
17019 //still 0 so first signal behind it also stays red. After that Attribute goes back to normal.
17020  int LockedVecNum = 0; //not used
17021  TPrefDirElement DummyPrefDir; //not used
17022  bool KeepAttributeAt0ForLockedRoute = false;
17023  if(AllRoutes->IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(15, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, DummyPrefDir,
17024  LockedVecNum))
17025  {
17026  Attribute = 0;
17027  KeepAttributeAt0ForLockedRoute = true;
17028  }
17029 //end of addition
17030  if(Attribute < 3)
17031  {
17032  Track->TrackElementAt(110, PrefDirPtr->TrackVectorPosition).Attribute = Attribute;
17033  }
17034  else
17035  {
17036  Track->TrackElementAt(111, PrefDirPtr->TrackVectorPosition).Attribute = 3; // green
17037  }
17038  Track->PlotSignal(1, Track->TrackElementAt(112, PrefDirPtr->TrackVectorPosition), Display);
17039  if(AllRoutes->GetRouteTypeAndGraphics(1, PrefDirPtr->TrackVectorPosition, PrefDirPtr->XLinkPos, EXGraphicPtr,
17040  EntryDirectionGraphicPtr) != TAllRoutes::NoRoute)
17041  {
17042  Display->PlotOutput(16, Track->TrackElementAt(113, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17043  Track->TrackElementAt(114, PrefDirPtr->TrackVectorPosition).VLoc * 16, EXGraphicPtr);
17044  Display->PlotOutput(17, Track->TrackElementAt(115, PrefDirPtr->TrackVectorPosition).HLoc * 16,
17045  Track->TrackElementAt(116, PrefDirPtr->TrackVectorPosition).VLoc * 16, EntryDirectionGraphicPtr);
17046  }
17047  if((Attribute < 3) && !KeepAttributeAt0ForLockedRoute)
17048  {
17049  Attribute++;
17050  }
17051  Display->Update(); // update after recent plots
17052  }
17053  }
17054  }
17055  }
17056  Utilities->CallLogPop(335);
17057  return(true);
17058 }
17059 
17060 // ---------------------------------------------------------------------------
17061 
17062 void TOneRoute::GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
17063 /*
17064  Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFlag value of NotInRoute.
17065  If it is in a route but the element selected is invalid, then a message is given and returns with a ReturnFlag value of
17066  InRouteFalse. Otherwise the route is truncated at and including the element that matches H & V with a ReturnFlag value of InRouteTrue.
17067  Selection invalid if select a bridge; trying to leave a single element; last element to be left
17068  not a signal (for PrefDirRoute or has AutoSigsFlag set); last element to be left a bridge, points or crossover (for not
17069  PrefDirRoute & AutoSigsFlag not set), or part of route locked. Check if a train approaching or occupying route and lock route
17070  if required after offering the user the choice to continue or not. Then SetAllRearwardsSignals is called to set signals before the
17071  truncate point, beginning with a red signal, and RemoveRouteElement called for all elements from the end to and including the truncate point.
17072 */
17073 {
17074  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTruncateElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
17075  "," + AnsiString((short)PrefDirRoute));
17076  bool ElementInRoute = false;
17077  bool TrainOccupyingRoute = false;
17078 
17079  for(unsigned int b = 0; b < PrefDirSize(); b++)
17080  {
17081  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17082  {
17083  ElementInRoute = true;
17084  break;
17085  }
17086  }
17087  if(!ElementInRoute)
17088  {
17089  ReturnFlag = NotInRoute;
17090  Utilities->CallLogPop(336);
17091  return;
17092  }
17093 // it is in the route so continue, first look for a train or a flashing level crossing
17094  for(int b = PrefDirSize() - 1; b >= 0; b--)
17095  {
17096  int TrainID = Track->TrackElementAt(117, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnElement;
17097  if(PrefDirVector.at(b).TrackType == Bridge)
17098  {
17099  if(PrefDirVector.at(b).XLinkPos < 2)
17100  {
17101  TrainID = Track->TrackElementAt(118, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos01;
17102  }
17103  else
17104  {
17105  TrainID = Track->TrackElementAt(119, PrefDirVector.at(b).TrackVectorPosition).TrainIDOnBridgeTrackPos23;
17106  }
17107  }
17108  if(TrainID != -1)
17109  {
17110 // TrainController->StopTTClockMessage(56, "Can't truncate a route that is occupied by a train");
17111 // ReturnFlag = InRouteFalse;
17112 // Utilities->CallLogPop(337);
17113 // return;
17114 // above removed at v2.1.0 so that routes can be locked when occupied, below added
17115  TrainOccupyingRoute = true; // train is forward of the truncate point
17116  }
17117  if(Track->IsLCBarrierFlashingAtHV(3, PrefDirVector.at(b).HLoc, PrefDirVector.at(b).VLoc))
17118  {
17119  TrainController->StopTTClockMessage(79, "Can't cancel a route containing a level crossing that is changing state");
17120  ReturnFlag = InRouteFalse;
17121  Utilities->CallLogPop(1941);
17122  return;
17123  }
17124  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc))
17125  {
17126  break; // OK found truncate element & no flashing LC in front
17127  }
17128  }
17129 
17130  for(unsigned int b = 0; b < PrefDirSize(); b++)
17131  {
17132  if((PrefDirVector.at(b).HLoc == HLoc) && (PrefDirVector.at(b).VLoc == VLoc)) // b = the truncate point
17133  {
17134  if(PrefDirVector.at(b).TrackType == Bridge)
17135  {
17136  TrainController->StopTTClockMessage(57, "Can't select a bridge as a route truncate point");
17137  ReturnFlag = InRouteFalse;
17138  Utilities->CallLogPop(338);
17139  return;
17140  }
17141  if(b == 1)
17142  {
17143  TrainController->StopTTClockMessage(58, "Can't truncate to a single route element");
17144  ReturnFlag = InRouteFalse;
17145  Utilities->CallLogPop(339);
17146  return;
17147  }
17148  if(b > 0)
17149  {
17150  TPrefDirElement TempElement = PrefDirVector.at(b - 1);
17151  if(TempElement.PrefDirRoute || TempElement.AutoSignals)
17152  {
17153  if(TempElement.Config[TempElement.XLinkPos] != Signal)
17154  {
17155  TrainController->StopTTClockMessage(59, "Must truncate to a valid signal - select position after signal");
17156  ReturnFlag = InRouteFalse;
17157  Utilities->CallLogPop(340);
17158  return;
17159  }
17160  }
17161  else
17162  {
17163  if((TempElement.TrackType == Points) || (TempElement.TrackType == Crossover) || (TempElement.TrackType == Bridge))
17164  {
17165  TrainController->StopTTClockMessage(60, "Can't truncate to points, bridge or crossover");
17166  ReturnFlag = InRouteFalse;
17167  Utilities->CallLogPop(341);
17168  return;
17169  }
17170  }
17171  }
17172  int RouteNumber;
17174 // Have to call RouteLockingRequired before SetAllRearwardsSignals because RouteLockingRequired tests the first rearward signal, if it is
17175 // red then locking is not required, and if call SetAllRearwardsSignals first then it will set the first rearward signal to red.
17176 
17177 // check if part of this route already locked & disallow if so
17178  if(!(AllRoutes->LockedRouteVector.empty()))
17179  {
17181  {
17182  if(LRVIT->RouteNumber == RouteNumber)
17183  {
17184  TrainController->StopTTClockMessage(61, "Can't truncate a route that is already part-locked");
17185  ReturnFlag = InRouteFalse;
17186  Utilities->CallLogPop(749);
17187  return;
17188  }
17189  }
17190  }
17191  if(AllRoutes->RouteLockingRequired(0, RouteNumber, b) || TrainOccupyingRoute) // added TrainOccupyingRoute at v2.1.0,
17192  // RouteLockingRequired only checks for trains approaching
17193  {
17196  int button = Application->MessageBox(L"Train approaching or occupying route, YES to lock route (2 minutes to release), NO to cancel",
17197  L"Warning!", MB_YESNO | MB_ICONWARNING);
17198  TrainController->BaseTime = TDateTime::CurrentDateTime();
17200  if(button == IDNO)
17201  {
17202  ReturnFlag = InRouteTrue; // still return true even though don't act on it
17203  Utilities->CallLogPop(342);
17204  return;
17205  }
17206  AnsiString LocID = AnsiString(Track->TrackElementAt(534, PrefDirVector.at(b).TrackVectorPosition).ElementID);
17207  TrainController->LogActionError(0, "", "", FailLockedRoute, LocID);
17208  TAllRoutes::TLockedRouteClass LockedRoute;
17209  bool ExistingLockedRouteModified = false;
17210  LockedRoute.RouteNumber = RouteNumber;
17211  LockedRoute.TruncateTrackVectorPosition = PrefDirVector.at(b).TrackVectorPosition;
17212  LockedRoute.LastTrackVectorPosition = PrefDirVector.at(PrefDirSize() - 1).TrackVectorPosition;
17213  LockedRoute.LastXLinkPos = PrefDirVector.at(PrefDirSize() - 1).XLinkPos;
17214  LockedRoute.LockStartTime = TrainController->TTClockTime;
17215 // but first check if this route already in LockedRouteVector (i.e. locked further along), and if so just change that vector entry
17216 // to use the new TruncateTrackVectorPosition & LockStartTime
17217  if(!AllRoutes->LockedRouteVector.empty())
17218  {
17219  for(TAllRoutes::TLockedRouteVectorIterator LRVIT = AllRoutes->LockedRouteVector.begin(); LRVIT < AllRoutes->LockedRouteVector.end();
17220  LRVIT++)
17221  {
17222  if(LRVIT->RouteNumber == RouteNumber)
17223  {
17224  LRVIT->TruncateTrackVectorPosition = LockedRoute.TruncateTrackVectorPosition;
17225  LRVIT->LockStartTime = LockedRoute.LockStartTime;
17226  ExistingLockedRouteModified = true;
17227  }
17228  }
17229  }
17230  if(!ExistingLockedRouteModified)
17231  {
17232  AllRoutes->LockedRouteVector.push_back(LockedRoute);
17233  }
17234  AllRoutes->SetAllRearwardsSignals(2, 0, RouteNumber, b);
17235  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17236  {
17237  // return all signals to red in route section to be truncated
17238  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(61, RouteNumber).PrefDirVector.at(c);
17239  TTrackElement & TrackElement = Track->TrackElementAt(120, PrefDirElement.TrackVectorPosition);
17240  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal)
17241  {
17242  TrackElement.Attribute = 0;
17243  Track->PlotSignal(2, TrackElement, Display);
17244  Display->PlotOutput(18, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EXGraphicPtr);
17245  Display->PlotOutput(19, PrefDirElement.HLoc * 16, PrefDirElement.VLoc * 16, PrefDirElement.EntryDirectionGraphicPtr);
17246  }
17247  }
17248 // Display->Update();//not needed as Clearand... called on return from GetAllRoutesTruncateElement in InterfaceUnit
17249  ReturnFlag = InRouteTrue;
17250  }
17251  else
17252  {
17253  AllRoutes->SetAllRearwardsSignals(3, 0, RouteNumber, b);
17254  for(int c = PrefDirSize() - 1; c >= (int)b; c--) // must use int for >= test to succeed when b == 0
17255  {
17256  AllRoutes->RemoveRouteElement(5, LastElementPtr(3)->HLoc, LastElementPtr(4)->VLoc, LastElementPtr(5)->ELink);
17257  ReturnFlag = InRouteTrue;
17258  }
17259  }
17260  AllRoutes->CheckMapAndRoutes(5); // test
17261  Utilities->CallLogPop(343);
17262  return;
17263  }
17264  }
17265  ReturnFlag = NotInRoute;
17266  Utilities->CallLogPop(344);
17267 }
17268 
17269 // ---------------------------------------------------------------------------
17271 /*
17272  This is used when a train enters a route set in the opposite direction of travel (or at a crossover on a non-route line when the other
17273  track is in a route). The complete route is cancelled (but not linked routes), and all signals in the route are set to red.
17274  First all signals are set to red and replotted (without any route colours), then SetAllRearwardsSignals is called from the
17275  beginning of the route to set all linked rearwards route signals appropriately. Then all elements are removed from the route
17276  and RebuildRailwayFlag set (examined in Interface unit at each clock tick) to force a ClearandRebuildRailway to get rid of
17277  the route colours.
17278 */
17279 {
17280  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ForceCancelRoute");
17281  TrainController->StopTTClockFlag = true; // so TTClock stopped during MasterClockTimer function
17283  int RouteNumber;
17284  TAllRoutes::TRouteType RouteType = AllRoutes->GetRouteTypeAndNumber(4, GetFixedPrefDirElementAt(86, 0).TrackVectorPosition,
17285  GetFixedPrefDirElementAt(87, 0).XLinkPos, RouteNumber);
17286 
17287  if(RouteType != TAllRoutes::NoRoute) // it won't be, above only used to get RouteNumber for setting rearwards signals
17288  {
17289  for(unsigned int x = 0; x < PrefDirSize(); x++) // set all signals in route to red regardless of direction
17290  {
17291  if(PrefDirVector.at(x).TrackType == SignalPost)
17292  {
17293  Track->TrackElementAt(121, PrefDirVector.at(x).TrackVectorPosition).Attribute = 0; // red
17294  Track->PlotSignal(3, Track->TrackElementAt(122, PrefDirVector.at(x).TrackVectorPosition), Display);
17295  }
17296  }
17297  AllRoutes->SetAllRearwardsSignals(4, 0, RouteNumber, 0);
17298 // already set all signals to red in route so start at start of route for further rearwards signal setting
17299  }
17300  for(int c = PrefDirSize() - 1; c >= 0; c--) // must use int for >= test to succeed when b == 0
17301  {
17302  AllRoutes->RemoveRouteElement(6, LastElementPtr(6)->HLoc, LastElementPtr(7)->VLoc, LastElementPtr(8)->ELink);
17303  }
17304  AllRoutes->RebuildRailwayFlag = true; // set to force a ClearandRebuildRailway at next clock tick if not in zoom-out mode
17305  AllRoutes->CheckMapAndRoutes(9); // test
17306  TrainController->BaseTime = TDateTime::CurrentDateTime();
17308  Utilities->CallLogPop(345);
17309  return;
17310 }
17311 
17312 // ---------------------------------------------------------------------------
17313 
17314 void TOneRoute::SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17315 /*
17316  Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector.
17317 */
17318 {
17319  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteSearchVectorGraphics," + AnsiString((short)AutoSigsFlag) + "," +
17320  AnsiString((short)PrefDirRoute));
17321  if(SearchVector.empty())
17322  {
17323  Utilities->CallLogPop(1149);
17324  return;
17325  }
17326  for(unsigned int b = 0; b < SearchVector.size(); b++)
17327  {
17330  PrefDirRoute);
17331  }
17332  Utilities->CallLogPop(346);
17333 }
17334 
17335 // ---------------------------------------------------------------------------
17336 
17337 void TOneRoute::SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
17338 /*
17339  Sets all element values in the RouteFlashVector (member of class TRouteFlash - defined in TOneRoute, of which
17340  TOneRoute has one member called RouteFlash) from the SearchVector. TRouteFlashElement is also a class defined in
17341  TOneRoute.
17342 */
17343 {
17344  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetRouteAndLCChangeValues," + AnsiString((short)AutoSigsFlag) + "," +
17345  AnsiString((short)PrefDirRoute));
17346  RouteFlash.RouteFlashVector.clear();
17347  TRouteFlashElement RouteFlashElement;
17348 
17349  for(unsigned int b = 0; b < SearchVector.size(); b++)
17350  {
17351  int H = GetFixedSearchElementAt(11, b).HLoc;
17352  int V = GetFixedSearchElementAt(12, b).VLoc;
17354  RouteFlashElement.OverlayGraphic = GetModifiableSearchElementAt(6, b).GetRouteGraphicPtr(AutoSigsFlag, PrefDirRoute);
17355  RouteFlashElement.HLoc = H;
17356  RouteFlashElement.VLoc = V;
17358  RouteFlash.RouteFlashVector.push_back(RouteFlashElement);
17359  }
17360  Utilities->CallLogPop(348);
17361 }
17362 
17363 // ---------------------------------------------------------------------------
17364 
17365 void TOneRoute::SetLCChangeValues(int Caller, bool PrefDirRoute) //used when setting routes to start any included LC's lowering
17366 {
17367  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetLCChangeValues," + AnsiString((short)PrefDirRoute));
17368  if(!PrefDirVector.empty())
17369  {
17370  for(TPrefDirVectorConstIterator PrefDirPtr = (PrefDirVector.end() - 1); PrefDirPtr >= PrefDirVector.begin(); PrefDirPtr--)
17371  {
17372  int H = PrefDirPtr->HLoc;
17373  int V = PrefDirPtr->VLoc;
17374  // check for any LCs that are closed to trains & set the flash values and store in the vector
17375  if(Track->IsLCAtHV(39, H, V))
17376  {
17377  if(Track->IsLCBarrierUpAtHV(0, H, V))
17378  {
17379  Track->LCChangeFlag = true;
17380  TTrack::TActiveLevelCrossing CLC; // constructor sets ReducedTimePenalty to false
17381  CLC.HLoc = H;
17382  CLC.VLoc = V;
17384  CLC.BaseElementSpeedTag = PrefDirPtr->SpeedTag;
17387  if(PrefDirRoute)
17388  {
17389  CLC.TypeOfRoute = 1;
17390  }
17391  Track->SetLinkedLevelCrossingBarrierAttributes(1, H, V, 2); // set attr to 2 for changing state
17392  Track->ChangingLCVector.push_back(CLC);
17393  }
17394  }
17395  }
17396  }
17397  Utilities->CallLogPop(1948);
17398 }
17399 
17400 // ---------------------------------------------------------------------------
17401 
17403 /*
17404  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17405  checks first whether the OverlayPlotted flag is set and if not plots the OverlayGraphic for all
17406  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17407  is set. The OverlayGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17408 */
17409 {
17410  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOverlay");
17411  if(!OverlayPlotted)
17412  {
17413  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17414  {
17415  if(Track->TrackElementAt(123, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17416  {
17417  continue;
17418  }
17419  Display->PlotOutput(20, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OverlayGraphic);
17420  Display->Update();
17421  }
17422  OverlayPlotted = true;
17423  }
17424  Utilities->CallLogPop(349);
17425 }
17426 
17427 // ---------------------------------------------------------------------------
17428 
17430 /*
17431  Class TRouteFlash is defined in TOneRoute, which has one member called RouteFlash. This function
17432  checks first whether the OverlayPlotted flag is set and if so plots the OriginalGraphic for all
17433  elements in the RouteFlashVector, skipping any that a train is on. Finally the OverlayPlotted flag
17434  is reset. The OriginalGraphic is set during TOneRoute::SetRouteAndLCChangeValues().
17435 */
17436 {
17437  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TRouteFlash::PlotRouteOriginal");
17438  if(OverlayPlotted)
17439  {
17440  for(unsigned int x = 0; x < RouteFlashVector.size(); x++)
17441  {
17442  if(Track->TrackElementAt(124, RouteFlashVector.at(x).TrackVectorPosition).TrainIDOnElement > -1)
17443  {
17444  continue;
17445  }
17446  Display->PlotOutput(21, RouteFlashVector.at(x).HLoc * 16, RouteFlashVector.at(x).VLoc * 16, RouteFlashVector.at(x).OriginalGraphic);
17447  Display->Update();
17448  }
17449  OverlayPlotted = false;
17450  }
17451  Utilities->CallLogPop(350);
17452 }
17453 
17454 // ---------------------------------------------------------------------------
17455 
17456 const TOneRoute &TAllRoutes::GetFixedRouteAt(int Caller, int At) const
17457 {
17458  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAt," + AnsiString(At));
17459  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17460  {
17461  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetFixedRouteAt");
17462  }
17463  Utilities->CallLogPop(120);
17464  return(AllRoutesVector.at(At));
17465 }
17466 
17467 // ---------------------------------------------------------------------------
17468 // ---------------------------------------------------------------------------
17469 
17471 {
17472  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteAt," + AnsiString(At));
17473  if((At < 0) || ((unsigned int)At >= AllRoutesVector.size()))
17474  {
17475  throw Exception("Out of Range Error, vector size: " + AnsiString(AllRoutesVector.size()) + ", At: " + AnsiString(At) + " in GetModifiableRouteAt");
17476  }
17477  Utilities->CallLogPop(121);
17478  return(AllRoutesVector.at(At));
17479 }
17480 
17481 // ---------------------------------------------------------------------------
17482 
17483 void TAllRoutes::MarkAllRoutes(int Caller, TDisplay *Disp)
17484 /*
17485  Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir false.
17486 */
17487 {
17488  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",MarkAllRoutes");
17489  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17490  {
17491  GetFixedRouteAt(62, a).PrefDirMarker(7, RouteCall, false, Disp);
17492  }
17493  Utilities->CallLogPop(351);
17494 }
17495 
17496 // ---------------------------------------------------------------------------
17497 
17498 void TAllRoutes::WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
17499 {
17500  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",WriteAllRoutesToImage");
17501  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17502  {
17503  GetFixedRouteAt(166, a).RouteImageMarker(0, Bitmap);
17504  }
17505  Utilities->CallLogPop(1706);
17506 }
17507 
17508 // ---------------------------------------------------------------------------
17509 
17510 bool TAllRoutes::GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
17511 /*
17512  Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is present in
17513  that route. The ReturnFlag value indicates InRouteTrue (success), InRouteFalse (failure), or NotInRoute.
17514  Messages are given in GetRouteTruncateElement. If successful the route is truncated at and including
17515  the element that matches H & V. If PrefDirRoute ensure only truncate to a signal, else prevent
17516  truncation to a crossover, bridge or points, also prevent route being left less than 2 elements in
17517  length (train length).
17518 */
17519 {
17520  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetAllRoutesTruncateElement," + AnsiString(HLoc) + "," +
17521  AnsiString(VLoc) + "," + AnsiString((short)PrefDirRoute));
17522  for(unsigned int a = 0; a < AllRoutesSize(); a++)
17523  {
17524  TTruncateReturnType ReturnFlag;
17525  RouteTruncateFlag = true;
17526 // used in SetRearwardsSignalsReturnFalseForTrain (called by GetRouteTruncateElement) to skip continuation & buffer attribute change
17527  GetModifiableRouteAt(7, a).GetRouteTruncateElement(0, HLoc, VLoc, PrefDirRoute, ReturnFlag);
17528  RouteTruncateFlag = false;
17529  if(ReturnFlag == NotInRoute)
17530  {
17531  continue;
17532  }
17533  else if(ReturnFlag == InRouteTrue)
17534  {
17535  Utilities->CallLogPop(352);
17536  return(true);
17537  }
17538  else if(ReturnFlag == InRouteFalse)
17539  {
17540  Utilities->CallLogPop(353);
17541  return(false);
17542  }
17543  }
17544  Utilities->CallLogPop(354);
17545  return(false);
17546 }
17547 
17548 // ---------------------------------------------------------------------------
17549 
17550 bool TAllRoutes::TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
17551 /*
17552  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)
17553  is found it returns true (for crossovers & points returns true whichever track the route is on), else returns false.
17554 */
17555 {
17556  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",TrackIsInARoute," + AnsiString(TrackVectorPosition) + "," +
17557  AnsiString(LinkPos));
17558  if(TrackVectorPosition == -1) // allows for continuation entries & exits
17559  {
17560  Utilities->CallLogPop(355);
17561  return(false);
17562  }
17563  THVPair Route2MultiMapKeyPair;
17564 
17565  Route2MultiMapKeyPair.first = Track->TrackElementAt(125, TrackVectorPosition).HLoc;
17566  Route2MultiMapKeyPair.second = Track->TrackElementAt(126, TrackVectorPosition).VLoc;
17567  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17568  TRoute2MultiMapIterator Route2MultiMapIterator;
17569 
17570  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0) // none found
17571  {
17572  Utilities->CallLogPop(356);
17573  return(false);
17574  }
17575  if(Track->TrackElementAt(706, TrackVectorPosition).TrackType != Bridge) // if not a bridge doesn't matter which track the route is on
17576  {
17577  Utilities->CallLogPop(1422);
17578  return(true);
17579  }
17580  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17581  {
17582  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17583 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17584 // realised after writing this that can't be points as would have been covered above, but leave anyway
17585  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(64, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(88,
17586  Route2MultiMapIterator->second.second);
17587  EntryLinkPos = PrefDirElement1.ELinkPos;
17588  ExitLinkPos = PrefDirElement1.XLinkPos;
17589  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17590  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17591  if(EntryLink == Track->TrackElementAt(127, TrackVectorPosition).Link[LinkPos])
17592  {
17593  Utilities->CallLogPop(357);
17594  return(true);
17595  }
17596  if(ExitLink == Track->TrackElementAt(128, TrackVectorPosition).Link[LinkPos])
17597  {
17598  Utilities->CallLogPop(358);
17599  return(true);
17600  }
17601  }
17602  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2) // if both tracks in route then must return true
17603  {
17604  Utilities->CallLogPop(1423);
17605  return(true);
17606  }
17607  Utilities->CallLogPop(363);
17608  return(false); // none found
17609 }
17610 
17611 // ---------------------------------------------------------------------------
17612 
17613 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap* &EXGraphicPtr,
17614  Graphics::TBitmap* &EntryDirectionGraphicPtr)
17615 /*
17616  Examines Route2MultiMap and if finds the element at TrackVectorPosition with LinkPos (can be entry or exit) returns the appropriate route
17617  type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute. If element not found then NoRoute is returned. If element is in a route then the EXGraphicPtr
17618  is returned, and if either the start or end of a route then the correct EntryDirectionGraphicPtr is returned, else a transparent element is returned.
17619  Function is used in TrainUnit for retaining AutoSigsRoutes but erasing others after train passes, and for picking up the correct background graphics
17620  for replotting of AutoSigsRoutes.
17621 */
17622 {
17623  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndGraphics," + AnsiString(TrackVectorPosition) + "," +
17624  AnsiString(LinkPos));
17625  EXGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17626  EntryDirectionGraphicPtr = RailGraphics->bmTransparentBgnd; // default value
17627  if(TrackVectorPosition == -1)
17628  {
17629  Utilities->CallLogPop(364);
17630  return(NoRoute); // allows for continuation entries & exits
17631  }
17632  THVPair Route2MultiMapKeyPair;
17633 
17634  Route2MultiMapKeyPair.first = Track->TrackElementAt(133, TrackVectorPosition).HLoc;
17635  Route2MultiMapKeyPair.second = Track->TrackElementAt(134, TrackVectorPosition).VLoc;
17636  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17637  TRoute2MultiMapIterator Route2MultiMapIterator;
17638 
17639  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17640  {
17641  Utilities->CallLogPop(365);
17642  return(NoRoute); // none found
17643  }
17644  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17645  {
17646  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17647 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17648  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(73, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(97,
17649  Route2MultiMapIterator->second.second);
17650  EntryLinkPos = PrefDirElement1.ELinkPos;
17651  ExitLinkPos = PrefDirElement1.XLinkPos;
17652  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17653  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17654  if(EntryLink == Track->TrackElementAt(135, TrackVectorPosition).Link[LinkPos])
17655  {
17656  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17657  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(74,
17658  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17659  {
17660  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17661  }
17662  if(PrefDirElement1.AutoSignals)
17663  {
17664  Utilities->CallLogPop(366);
17665  return(AutoSigsRoute);
17666  }
17667  else
17668  {
17669  Utilities->CallLogPop(367);
17670  return(NotAutoSigsRoute);
17671  }
17672  }
17673  if(ExitLink == Track->TrackElementAt(136, TrackVectorPosition).Link[LinkPos])
17674  {
17675  EXGraphicPtr = PrefDirElement1.EXGraphicPtr;
17676  if((Route2MultiMapIterator->second.second == 0) || (Route2MultiMapIterator->second.second == GetFixedRouteAt(75,
17677  Route2MultiMapIterator->second.first).PrefDirSize() - 1))
17678  {
17679  EntryDirectionGraphicPtr = PrefDirElement1.EntryDirectionGraphicPtr;
17680  }
17681  if(PrefDirElement1.AutoSignals)
17682  {
17683  Utilities->CallLogPop(368);
17684  return(AutoSigsRoute);
17685  }
17686  else
17687  {
17688  Utilities->CallLogPop(369);
17689  return(NotAutoSigsRoute);
17690  }
17691  }
17692  }
17693  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17694  {
17695  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17696  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17697 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17698  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(76, ItPair.first->second.first).GetFixedPrefDirElementAt(98, ItPair.first->second.second);
17699  EntryLinkPos = PrefDirElement2.ELinkPos;
17700  ExitLinkPos = PrefDirElement2.XLinkPos;
17701  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17702  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17703  if(EntryLink == Track->TrackElementAt(137, TrackVectorPosition).Link[LinkPos])
17704  {
17705  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17706  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(77, ItPair.first->second.first).PrefDirSize() - 1))
17707  {
17708  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17709  }
17710  if(PrefDirElement2.AutoSignals)
17711  {
17712  Utilities->CallLogPop(370);
17713  return(AutoSigsRoute);
17714  }
17715  else
17716  {
17717  Utilities->CallLogPop(371);
17718  return(NotAutoSigsRoute);
17719  }
17720  }
17721  if(ExitLink == Track->TrackElementAt(138, TrackVectorPosition).Link[LinkPos])
17722  {
17723  EXGraphicPtr = PrefDirElement2.EXGraphicPtr;
17724  if((ItPair.first->second.second == 0) || (ItPair.first->second.second == GetFixedRouteAt(78, ItPair.first->second.first).PrefDirSize() - 1))
17725  {
17726  EntryDirectionGraphicPtr = PrefDirElement2.EntryDirectionGraphicPtr;
17727  }
17728  if(PrefDirElement2.AutoSignals)
17729  {
17730  Utilities->CallLogPop(372);
17731  return(AutoSigsRoute);
17732  }
17733  else
17734  {
17735  Utilities->CallLogPop(373);
17736  return(NotAutoSigsRoute);
17737  }
17738  }
17739  ItPair.second--; // the second iterator points one past the last matching value
17740  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(79, ItPair.second->second.first).GetFixedPrefDirElementAt(99, ItPair.second->second.second);
17741  EntryLinkPos = PrefDirElement3.ELinkPos;
17742  ExitLinkPos = PrefDirElement3.XLinkPos;
17743  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17744  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17745  if(EntryLink == Track->TrackElementAt(139, TrackVectorPosition).Link[LinkPos])
17746  {
17747  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17748  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(80, ItPair.second->second.first).PrefDirSize() - 1))
17749  {
17750  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17751  }
17752  if(PrefDirElement3.AutoSignals)
17753  {
17754  Utilities->CallLogPop(374);
17755  return(AutoSigsRoute);
17756  }
17757  else
17758  {
17759  Utilities->CallLogPop(375);
17760  return(NotAutoSigsRoute);
17761  }
17762  }
17763  if(ExitLink == Track->TrackElementAt(140, TrackVectorPosition).Link[LinkPos])
17764  {
17765  EXGraphicPtr = PrefDirElement3.EXGraphicPtr;
17766  if((ItPair.second->second.second == 0) || (ItPair.second->second.second == GetFixedRouteAt(81, ItPair.second->second.first).PrefDirSize() - 1))
17767  {
17768  EntryDirectionGraphicPtr = PrefDirElement3.EntryDirectionGraphicPtr;
17769  }
17770  if(PrefDirElement3.AutoSignals)
17771  {
17772  Utilities->CallLogPop(376);
17773  return(AutoSigsRoute);
17774  }
17775  else
17776  {
17777  Utilities->CallLogPop(377);
17778  return(NotAutoSigsRoute);
17779  }
17780  }
17781  }
17782  Utilities->CallLogPop(378);
17783  return(NoRoute); // none found
17784 }
17785 
17786 // ---------------------------------------------------------------------------
17787 TAllRoutes::TRouteType TAllRoutes::GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
17788 /*
17789  Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit) is found returns the appropriate
17790  route type - NoRoute, NotAutoSigsRoute, or AutoSigsRoute and number.
17791 */
17792 {
17793  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteTypeAndNumber," + AnsiString(TrackVectorPosition) + "," +
17794  AnsiString(LinkPos));
17795  if(TrackVectorPosition == -1)
17796  {
17797  RouteNumber = -1;
17798  Utilities->CallLogPop(379);
17799  return(NoRoute); // allows for continuation & buffer entries & exits
17800  }
17801  THVPair Route2MultiMapKeyPair;
17802 
17803  Route2MultiMapKeyPair.first = Track->TrackElementAt(141, TrackVectorPosition).HLoc;
17804  Route2MultiMapKeyPair.second = Track->TrackElementAt(142, TrackVectorPosition).VLoc;
17805  int EntryLink, EntryLinkPos, ExitLink, ExitLinkPos;
17806  TRoute2MultiMapIterator Route2MultiMapIterator;
17807 
17808  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
17809  {
17810  RouteNumber = -1;
17811  Utilities->CallLogPop(380);
17812  return(NoRoute); // none found
17813  }
17814  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
17815  {
17816  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
17817 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17818  const TPrefDirElement &PrefDirElement1 = GetFixedRouteAt(82, Route2MultiMapIterator->second.first).GetFixedPrefDirElementAt(100,
17819  Route2MultiMapIterator->second.second);
17820  EntryLinkPos = PrefDirElement1.ELinkPos;
17821  ExitLinkPos = PrefDirElement1.XLinkPos;
17822  EntryLink = PrefDirElement1.Link[EntryLinkPos];
17823  ExitLink = PrefDirElement1.Link[ExitLinkPos];
17824  if(EntryLink == Track->TrackElementAt(143, TrackVectorPosition).Link[LinkPos])
17825  {
17826  RouteNumber = Route2MultiMapIterator->second.first;
17827  if(PrefDirElement1.AutoSignals)
17828  {
17829  Utilities->CallLogPop(381);
17830  return(AutoSigsRoute);
17831  }
17832  else
17833  {
17834  Utilities->CallLogPop(382);
17835  return(NotAutoSigsRoute);
17836  }
17837  }
17838  if(ExitLink == Track->TrackElementAt(144, TrackVectorPosition).Link[LinkPos])
17839  {
17840  RouteNumber = Route2MultiMapIterator->second.first;
17841  if(PrefDirElement1.AutoSignals)
17842  {
17843  Utilities->CallLogPop(383);
17844  return(AutoSigsRoute);
17845  }
17846  else
17847  {
17848  Utilities->CallLogPop(384);
17849  return(NotAutoSigsRoute);
17850  }
17851  }
17852  }
17853  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
17854  {
17855  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
17856  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
17857 // check actual link rather than just LinkPos, since if points LinkPos could be 0 or 2 so may not match ELinkPos or XLinkPos, but both refer to same link
17858  const TPrefDirElement &PrefDirElement2 = GetFixedRouteAt(83, ItPair.first->second.first).GetFixedPrefDirElementAt(101, ItPair.first->second.second);
17859  EntryLinkPos = PrefDirElement2.ELinkPos;
17860  ExitLinkPos = PrefDirElement2.XLinkPos;
17861  EntryLink = PrefDirElement2.Link[EntryLinkPos];
17862  ExitLink = PrefDirElement2.Link[ExitLinkPos];
17863  if(EntryLink == Track->TrackElementAt(145, TrackVectorPosition).Link[LinkPos])
17864  {
17865  RouteNumber = ItPair.first->second.first;
17866  if(PrefDirElement2.AutoSignals)
17867  {
17868  Utilities->CallLogPop(385);
17869  return(AutoSigsRoute);
17870  }
17871  else
17872  {
17873  Utilities->CallLogPop(386);
17874  return(NotAutoSigsRoute);
17875  }
17876  }
17877  if(ExitLink == Track->TrackElementAt(146, TrackVectorPosition).Link[LinkPos])
17878  {
17879  RouteNumber = ItPair.first->second.first;
17880  if(PrefDirElement2.AutoSignals)
17881  {
17882  Utilities->CallLogPop(387);
17883  return(AutoSigsRoute);
17884  }
17885  else
17886  {
17887  Utilities->CallLogPop(388);
17888  return(NotAutoSigsRoute);
17889  }
17890  }
17891  ItPair.second--; // the second iterator points one past the last matching value
17892  const TPrefDirElement &PrefDirElement3 = GetFixedRouteAt(84, ItPair.second->second.first).GetFixedPrefDirElementAt(102, ItPair.second->second.second);
17893  EntryLinkPos = PrefDirElement3.ELinkPos;
17894  ExitLinkPos = PrefDirElement3.XLinkPos;
17895  EntryLink = PrefDirElement3.Link[EntryLinkPos];
17896  ExitLink = PrefDirElement3.Link[ExitLinkPos];
17897  if(EntryLink == Track->TrackElementAt(147, TrackVectorPosition).Link[LinkPos])
17898  {
17899  RouteNumber = ItPair.second->second.first;
17900  if(PrefDirElement3.AutoSignals)
17901  {
17902  Utilities->CallLogPop(389);
17903  return(AutoSigsRoute);
17904  }
17905  else
17906  {
17907  Utilities->CallLogPop(390);
17908  return(NotAutoSigsRoute);
17909  }
17910  }
17911  if(ExitLink == Track->TrackElementAt(148, TrackVectorPosition).Link[LinkPos])
17912  {
17913  RouteNumber = ItPair.second->second.first;
17914  if(PrefDirElement3.AutoSignals)
17915  {
17916  Utilities->CallLogPop(391);
17917  return(AutoSigsRoute);
17918  }
17919  else
17920  {
17921  Utilities->CallLogPop(392);
17922  return(NotAutoSigsRoute);
17923  }
17924  }
17925  }
17926  RouteNumber = -1;
17927  Utilities->CallLogPop(393);
17928  return(NoRoute); // none found
17929 }
17930 
17931 // ---------------------------------------------------------------------------
17932 
17933 void TAllRoutes::StoreOneRoute(int Caller, TOneRoute *Route)
17934 /*
17935  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector, which, since it is the last to be added, will have
17936  a RouteNumber of AllRoutesSize() - 1. Then each element of the new route is added in turn using AddRouteElement,
17937  which uses HLoc, VLoc, ELink and RouteNumber to provide the information necessary to insert it into both PrefDirVector
17938  and Route2MultiMap.
17939 */
17940 {
17941  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRoute");
17942  TOneRoute EmptyRoute;
17943 
17944  EmptyRoute.RouteID = NextRouteID;
17945  NextRouteID++;
17946 
17947  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17948  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17949  {
17950  AddRouteElement(0, Route->GetFixedPrefDirElementAt(127, x).HLoc, Route->GetFixedPrefDirElementAt(128, x).VLoc,
17951  Route->GetFixedPrefDirElementAt(129, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(130, x));
17952  }
17953  int FirstVecPos = Route->GetFixedPrefDirElementAt(199, 0).TrackVectorPosition;
17954  int LastVecPos = Route->GetFixedPrefDirElementAt(200, (Route->PrefDirSize()) - 1).TrackVectorPosition;
17955 
17956  TrainController->LogEvent("StoreOneRoute," + AnsiString(EmptyRoute.RouteID) + "," + AnsiString(FirstVecPos) + "," + AnsiString(LastVecPos));
17957  Utilities->CallLogPop(394);
17958 }
17959 
17960 // ---------------------------------------------------------------------------
17961 
17963 /*
17964  A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load. For this the RouteID
17965  that is already in Route is used.
17966 */
17967 {
17968  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",StoreOneRouteAfterSessionLoad");
17969  TOneRoute EmptyRoute;
17970 
17971  EmptyRoute.RouteID = Route->RouteID;
17972 
17973  AllRoutesVector.push_back(EmptyRoute); // to create a new route vector entry
17974  for(unsigned int x = 0; x < Route->PrefDirSize(); x++)
17975  {
17976  AddRouteElement(3, Route->GetFixedPrefDirElementAt(189, x).HLoc, Route->GetFixedPrefDirElementAt(190, x).VLoc,
17977  Route->GetFixedPrefDirElementAt(191, x).GetELink(), AllRoutesSize() - 1, Route->GetFixedPrefDirElementAt(192, x));
17978  }
17979  Utilities->CallLogPop(1579);
17980 }
17981 
17982 // ---------------------------------------------------------------------------
17983 
17984 void TAllRoutes::ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
17985 /*
17986  When attaching a new route section to an existing route, it is sometimes necessary to erase the
17987  original route and create a new composite route. This function Erases all elements in the route
17988  at RouteNumber using TAllRoutes->RemoveRouteElement to clear elements from Route2MultiMap and
17989  from the PrefDirVector. Since all elements for the route are removed RemoveRouteElement also
17990  clears the Route from AllRoutesVector. Route numbers are decremented in the map for route numbers
17991  that are greater than the route number that is removed. The LockedRouteVector as also searched
17992  and if any relate to the route that has been cleared they are erased too, but the fact that one
17993  has been found is recorded so that it can be re-established later.
17994 */
17995 {
17996  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",ClearRouteDuringRouteBuildingAt," + AnsiString(RouteNumber));
17997  THVPair Route2MultiMapKeyPair;
17998  TRoute2MultiMapEntry Route2MultiMapEntry;
17999  TRoute2MultiMapIterator Route2MultiMapIterator;
18000 
18001 // need to check LockedVector first, and erase it if it's the route to be cleared, and to reinstate it as a new locked route with the same
18002 // values (except RouteNumber) when the new route is established (in ConvertAndAdd...).
18003 // If clear all route elements first then when the last is cleared the LockedVector.RouteNumber values are decremented if they are higher
18004 // then the cleared route number (by RemoveRouteElement), and one of the new values may be the same number as the old cleared route number.
18005 // If so the locked route is removed from the locked vector and is lost.
18006  LockedRouteTruncateTrackVectorPosition = 0;
18007  LockedRouteLastTrackVectorPosition = 0;
18008  LockedRouteLastXLinkPos = 0;
18009  LockedRouteLockStartTime = TDateTime(0);
18010  if(!LockedRouteVector.empty())
18011  {
18012  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18013  {
18014  if(LRVIT->RouteNumber == RouteNumber)
18015  {
18016  LockedRouteTruncateTrackVectorPosition = LRVIT->TruncateTrackVectorPosition;
18017  LockedRouteLastTrackVectorPosition = LRVIT->LastTrackVectorPosition;
18018  LockedRouteLastXLinkPos = LRVIT->LastXLinkPos;
18019  LockedRouteLockStartTime = LRVIT->LockStartTime;
18020  LockedRouteFoundDuringRouteBuilding = true;
18021  LockedRouteVector.erase(LRVIT);
18022  }
18023  }
18024  }
18025  for(int x = (AllRoutes->GetFixedRouteAt(109, RouteNumber).PrefDirSize()) - 1; x >= 0; x--)
18026  {
18027  TPrefDirElement PrefDirElement = AllRoutes->GetFixedRouteAt(110, RouteNumber).GetFixedPrefDirElementAt(131, x);
18028  AllRoutes->RemoveRouteElement(7, PrefDirElement.HLoc, PrefDirElement.VLoc, PrefDirElement.GetELink());
18029  }
18030  Utilities->CallLogPop(395);
18031 }
18032 
18033 // ---------------------------------------------------------------------------
18034 
18036  TRoute2MultiMapIterator &Route2MultiMapIterator)
18037 /*
18038  Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H, V and ELink.
18039  Also returned as a reference is an iterator to the found element in the map to assist in erasing it. Called by
18040  TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink). Note that only need ELink (as well as H & V) to
18041  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different. Messages
18042  are given for failure.
18043 */
18044 {
18045  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRoutePairFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18046  AnsiString(VLoc) + "," + AnsiString(ELink));
18047  TRouteElementPair ReturnPair;
18048 
18049  ReturnPair.first = -1;
18050  ReturnPair.second = 0;
18051  THVPair Route2MultiMapKeyPair;
18052 
18053  Route2MultiMapKeyPair.first = HLoc;
18054  Route2MultiMapKeyPair.second = VLoc;
18055  TRoute2MultiMapEntry Route2MultiMapEntry;
18056 
18057  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18058  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18059 
18060  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18061  Route2MultiMapIterator = ItPair.first;
18062 
18063  if(ItPair.first == ItPair.second)
18064  {
18065  throw Exception("Failed to find Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc);
18066  }
18067  if(GetFixedRouteAt(111, ItPair.first->second.first).GetFixedPrefDirElementAt(132, ItPair.first->second.second).GetELink() == ELink)
18068  {
18069  ReturnPair.first = ItPair.first->second.first;
18070  ReturnPair.second = ItPair.first->second.second;
18071  Route2MultiMapIterator = ItPair.first;
18072  Utilities->CallLogPop(396);
18073  return(ReturnPair);
18074  }
18075  ItPair.first++;
18076  if(ItPair.first == ItPair.second)
18077  {
18078  throw Exception("Found Route2MultiMap element at HLoc = " + (AnsiString)HLoc + " VLoc = " + (AnsiString)VLoc + " but failed to find required element");
18079  }
18080  if(GetFixedRouteAt(112, ItPair.first->second.first).GetFixedPrefDirElementAt(133, ItPair.first->second.second).GetELink() == ELink)
18081  {
18082  ReturnPair.first = ItPair.first->second.first;
18083  ReturnPair.second = ItPair.first->second.second;
18084  Route2MultiMapIterator = ItPair.first;
18085  Utilities->CallLogPop(397);
18086  return(ReturnPair);
18087  }
18088  Utilities->CallLogPop(398);
18089  return(ReturnPair);
18090 }
18091 
18092 // ---------------------------------------------------------------------------
18093 
18094 bool TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber) // new at v1.2.0
18095 /*
18096  Similar to above but returns a bool and no errors are reported for no route or element at H&V etc.
18097  Examines Route2MultiMap and returns true if a route is found with the passed values of H, V and ELink.
18098  RouteNumber (route position in AllRoutes vector is returned as a reference.
18099  Called by TTrain::CheckAndCancelRouteForWrongEndEntry. Note that only need ELink (as well as H & V) to
18100  identify uniquely, since only bridges can have two routes on them & their track ELinks are always different.
18101 */
18102 {
18103  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",FindRouteNumberFromRoute2MultiMapNoErrors," + AnsiString(HLoc) + "," +
18104  AnsiString(VLoc) + "," + AnsiString(ELink));
18105  THVPair Route2MultiMapKeyPair;
18106 
18107  Route2MultiMapKeyPair.first = HLoc;
18108  Route2MultiMapKeyPair.second = VLoc;
18109  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItPair;
18110 
18111  ItPair = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18112 
18113  if(ItPair.first == ItPair.second)
18114  {
18115  RouteNumber = -1;
18116  Utilities->CallLogPop(2032);
18117  return(false);
18118  }
18119  if(GetFixedRouteAt(205, ItPair.first->second.first).GetFixedPrefDirElementAt(241, ItPair.first->second.second).GetELink() == ELink)
18120  {
18121  RouteNumber = ItPair.first->second.first;
18122  Utilities->CallLogPop(2033);
18123  return(true);
18124  }
18125  ItPair.first++;
18126 
18127  if(ItPair.first == ItPair.second)
18128  {
18129  RouteNumber = -1;
18130  Utilities->CallLogPop(2034);
18131  return(false);
18132  }
18133  if(GetFixedRouteAt(206, ItPair.first->second.first).GetFixedPrefDirElementAt(242, ItPair.first->second.second).GetELink() == ELink)
18134  {
18135  RouteNumber = ItPair.first->second.first;
18136  Utilities->CallLogPop(2035);
18137  return(true);
18138  }
18139  RouteNumber = -1;
18140  Utilities->CallLogPop(2036);
18141  return(false);
18142 }
18143 
18144 // ---------------------------------------------------------------------------
18145 
18146 void TAllRoutes::Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
18147 /*
18148  Elink needed in case it's a bridge, & need to know whether the found element is on this route or not. First check if an
18149  entry in the map already exists at H & V, and if so check that it's a bridge with existing route on other track.
18150  That being so insert the new element. If it's not a bridge, or the route has the same ELink value as the element to
18151  be inserted, give appropriate messages. If there isn't an element at H & V already in the map insert it.
18152  Called by TAllRoutes::AddRouteElement.
18153 */
18154 {
18155  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",Route2MultiMapInsert," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
18156  "," + AnsiString(ELinkIn) + "," + AnsiString(RouteNumber) + "," + AnsiString(RouteElementNumber));
18157  THVPair Route2MultiMapKeyPair;
18158 
18159  Route2MultiMapKeyPair.first = HLoc;
18160  Route2MultiMapKeyPair.second = VLoc;
18161  TRoute2MultiMapEntry Route2MultiMapEntry;
18162 
18163  Route2MultiMapEntry.first = Route2MultiMapKeyPair;
18164  TRouteElementPair RouteElementPair;
18165 
18166  RouteElementPair.first = RouteNumber;
18167  RouteElementPair.second = RouteElementNumber;
18168  Route2MultiMapEntry.second = RouteElementPair;
18169 
18170  if(Route2MultiMap.find(Route2MultiMapKeyPair) != Route2MultiMap.end())
18171  // true for element at H&V already included in map, has to be a bridge with existing route on opposite track to be valid
18172  {
18173  if(GetFixedRouteAt(113, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(134,
18174  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).GetELink() != ELinkIn)
18175  // element already at H&V has different ELink to element to be inserted, so must be a bridge with existing route on opposite treack
18176  {
18177  if(GetFixedRouteAt(114, Route2MultiMap.find(Route2MultiMapKeyPair)->second.first).GetFixedPrefDirElementAt(135,
18178  Route2MultiMap.find(Route2MultiMapKeyPair)->second.second).TrackType != Bridge)
18179  {
18180  throw Exception("Error, bridge expected in Route2MultiMapInsert but not, at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18181  }
18182  Route2MultiMap.insert(Route2MultiMapEntry); // insert bridge into map again but now with the new track as part of required route
18183  }
18184  else
18185  // same ELink so have an error
18186  {
18187  throw Exception("Error, route map entry found in Route2MultiMapInsert at HLoc=" + AnsiString(HLoc) + " VLoc=" + AnsiString(VLoc));
18188  }
18189  }
18190  else
18191  {
18192  Route2MultiMap.insert(Route2MultiMapEntry);
18193  }
18194 // element at H&V not found in map so insert it
18195  Utilities->CallLogPop(399);
18196 }
18197 
18198 // ---------------------------------------------------------------------------
18199 
18201 /*
18202  Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function return
18203  and the second in the reference SecondPair. If there's only one then it's the function return
18204 */
18205 {
18206  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteElementDataFromRoute2MultiMap," + AnsiString(HLoc) + "," +
18207  AnsiString(VLoc));
18209 
18210  TempPair.first = -1;
18211  TempPair.second = 0;
18212  SecondPair = TempPair;
18213  TRoute2MultiMapIterator Route2MultiMapIterator;
18214  std::pair<TRoute2MultiMapIterator, TRoute2MultiMapIterator>ItRange;
18215  THVPair Route2MultiMapKeyPair;
18216 
18217  Route2MultiMapKeyPair.first = HLoc;
18218  Route2MultiMapKeyPair.second = VLoc;
18219  if(Route2MultiMap.count(Route2MultiMapKeyPair) == 0)
18220  {
18221  Utilities->CallLogPop(400);
18222  return(TempPair);
18223  }
18224  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 1)
18225  {
18226  Route2MultiMapIterator = Route2MultiMap.find(Route2MultiMapKeyPair);
18227  Utilities->CallLogPop(401);
18228  return(Route2MultiMapIterator->second);
18229  }
18230  else if(Route2MultiMap.count(Route2MultiMapKeyPair) == 2)
18231  {
18232  ItRange = Route2MultiMap.equal_range(Route2MultiMapKeyPair);
18233  TempPair = ItRange.first->second;
18234  SecondPair = (--ItRange.second)->second; // 2nd iterator points past the last value
18235  Utilities->CallLogPop(402);
18236  return(TempPair);
18237  }
18238  Utilities->CallLogPop(403);
18239  return(TempPair);
18240 }
18241 
18242 // ---------------------------------------------------------------------------
18243 
18244 void TAllRoutes::CheckMapAndRoutes(int Caller) // test
18245 /*
18246  Checks equivalence for each route between entries in PrefDirVector and those in Route2MultiMap, and also that the size
18247  of the multimap and the sum of the sizes of all PrefDirVectors is the same.
18248 */
18249 {
18250  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckMapAndRoutes");
18251  for(unsigned int a = 0; a < AllRoutes->AllRoutesSize(); a++)
18252  {
18253  for(unsigned int b = 0; b < AllRoutes->GetFixedRouteAt(115, a).PrefDirSize(); b++)
18254  {
18255  TPrefDirElement CheckElement = AllRoutes->GetFixedRouteAt(116, a).GetFixedPrefDirElementAt(136, b);
18256  TAllRoutes::TRouteElementPair SecondPair;
18257  TRouteElementPair RouteElementPair = GetRouteElementDataFromRoute2MultiMap(8, CheckElement.HLoc, CheckElement.VLoc, SecondPair);
18258  if(RouteElementPair.first == -1)
18259  // failed to find element in multimap
18260  {
18261  throw Exception("CheckMapAndRoutes Error - failed to find HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" + (AnsiString)CheckElement.VLoc +
18262  " in Route2MultiMap, Caller=" + (AnsiString)Caller);
18263  }
18264  if((RouteElementPair.first != (int)a) && (SecondPair.first != (int)a))
18265  // neither pair has expected route number
18266  {
18267  throw Exception("CheckMapAndRoutes Error - RouteNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18268  (AnsiString)CheckElement.VLoc + " Map value=" + (AnsiString)RouteElementPair.first + " Route value=" + (AnsiString)a + " Caller=" +
18269  (AnsiString)Caller);
18270  }
18271  if(((RouteElementPair.first != (int)a) || (RouteElementPair.second != b)) && ((SecondPair.first != (int)a) || (SecondPair.second != b)))
18272  // need one of pairs to match both RouteNumber and RouteElementNumber or fails
18273  {
18274  throw Exception("CheckMapAndRoutes Error - PrefDirVectorNumber failed at HLoc=" + (AnsiString)CheckElement.HLoc + " VLoc=" +
18275  (AnsiString)CheckElement.VLoc + " 1st Map value RouteNum/ElementNum =" + (AnsiString)RouteElementPair.first + "/" +
18276  (AnsiString)RouteElementPair.second + " 2nd Map value =" + (AnsiString)SecondPair.first + "/" + (AnsiString)SecondPair.second +
18277  " Route value=" + (AnsiString)a + "/" + (AnsiString)b + " Caller=" + (AnsiString)Caller);
18278  }
18279  }
18280  }
18281  unsigned int SizeVal = 0;
18282 
18283 // check map and sum of route sizes match
18284  for(unsigned int a = 0; a < AllRoutesSize(); a++)
18285  {
18286  SizeVal += GetFixedRouteAt(117, a).PrefDirSize();
18287  }
18288  if(SizeVal != Route2MultiMap.size())
18289  {
18290  throw Exception("CheckMapAndRoutes Error - Map Size=" + (AnsiString)Route2MultiMap.size() + " RouteSize=" + (AnsiString)SizeVal + " Caller=" +
18291  (AnsiString)Caller);
18292  }
18293  Utilities->CallLogPop(404);
18294  return;
18295 }
18296 
18297 // ---------------------------------------------------------------------------
18298 
18299 void TAllRoutes::DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
18300 /*
18301  After a route has been erased from AllRoutesVector and its entries from Route2MultiMap, this
18302  function examines all the remaining entries in Route2MultiMap to see if their RouteNumbers
18303  exceed that for the erased route. Where this is so the RouteNumber is decremented.
18304 */
18305 {
18306  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteNumbersInRoute2MultiMap," + AnsiString(RouteNumber));
18307  if(!Route2MultiMap.empty())
18308  {
18309  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18310  {
18311  if(Route2MultiMapIterator->second.first > RouteNumber)
18312  {
18313  Route2MultiMapIterator->second.first--;
18314  }
18315  }
18316  }
18317  Utilities->CallLogPop(405);
18318 }
18319 
18320 // ---------------------------------------------------------------------------
18321 
18322 void TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
18323 /*
18324  After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap, this
18325  function examines all the remaining entries in Route2MultiMap with the same RouteNumber as that
18326  for the erased element. Where a RouteElementNumber exceeds that for the erased element it is decremented.
18327 */
18328 {
18329  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DecrementRouteElementNumbersInRoute2MultiMap," +
18330  AnsiString(RouteNumber) + "," + AnsiString(ErasedElementNumber));
18331  if(!Route2MultiMap.empty())
18332  {
18333  for(TRoute2MultiMapIterator Route2MultiMapIterator = Route2MultiMap.begin(); Route2MultiMapIterator != Route2MultiMap.end(); Route2MultiMapIterator++)
18334  {
18335  if((Route2MultiMapIterator->second.first == RouteNumber) && (Route2MultiMapIterator->second.second > ErasedElementNumber))
18336  {
18337  Route2MultiMapIterator->second.second--;
18338  }
18339  }
18340  }
18341  Utilities->CallLogPop(406);
18342 }
18343 
18344 // ---------------------------------------------------------------------------
18345 
18346 void TAllRoutes::RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
18347 /*
18348  Erases the route element from Route2MultiMap and from the PrefDirVector.
18349  If there are no elements left in the PrefDirVector the route is cleared from AllRoutesVector. Route element numbers in the map are
18350  decremented if they are greater than the element number removed, and if the entire route is removed
18351  then the route numbers are also decremented in the map for route numbers that are greater than the route
18352  number that is removed.
18353 */
18354 {
18355  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RemoveRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18356  AnsiString(ELink));
18357  TRouteElementPair RequiredRoutePair; // RouteNumber & RouteElementNumber
18358  TRoute2MultiMapIterator Route2MultiMapIterator;
18359 
18360  RequiredRoutePair = FindRoutePairFromRoute2MultiMap(0, HLoc, VLoc, ELink, Route2MultiMapIterator);
18361  if(RequiredRoutePair.first == -1)
18362  {
18363  throw Exception("Failed to find route element in RemoveRouteElement");
18364  }
18365  Route2MultiMap.erase(Route2MultiMapIterator);
18366  DecrementRouteElementNumbersInRoute2MultiMap(0, RequiredRoutePair.first, RequiredRoutePair.second);
18367 
18368 // even though element has been erased from the routemap, RequiredRoutePair still contains the element values
18369  TPrefDirElement LockedRouteElement, PrefDirElement = GetFixedRouteAt(118, RequiredRoutePair.first).GetFixedPrefDirElementAt(137, RequiredRoutePair.second);
18370 
18371  if(Track->TrackElementAt(157, PrefDirElement.TrackVectorPosition).Config[PrefDirElement.XLinkPos] == Signal)
18372  {
18373  Track->TrackElementAt(158, PrefDirElement.TrackVectorPosition).Attribute = 0; // change forward signals back to red
18374  }
18375 // don't need the section below (a) because when a train removes elements from the front of a locked route, there is a test in
18376 // ApproachLocking to determine whether the element immediately nearer the start of the route to the element being removed is still
18377 // present, and of not the element removal stops; and (b) because it never worked anyway! - IsElementInLockedRoute.... uses Route2MultiMap
18378 // to check if a route element is present, and the element has already been removed from the map - see above.
18379 
18380 // before erase the element check if it's in a locked route, and if so change the TruncateTrackVectorPosition to the next valid (XLinkPos] element position
18381 /*
18382  int LockedVectorNumber = -1;
18383  if(IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(5, PrefDirElement.TrackVectorPosition, PrefDirElement.XLinkPos, LockedRouteElement, LockedVectorNumber))
18384  {
18385  LockedRouteVector.at(LockedVectorNumber).TruncateTrackVectorPosition = PrefDirElement.Conn[PrefDirElement.XLinkPos];
18386  }
18387 */
18388 
18389 // erase element from route
18390  GetModifiableRouteAt(8, RequiredRoutePair.first).EraseRouteElementAt(&(GetModifiableRouteAt(9, RequiredRoutePair.first).GetModifiablePrefDirElementAt(1,
18391  RequiredRoutePair.second)));
18392 // CheckMapAndRoutes();//test - drop - tested below
18393 
18394 // remove ContinuationAutoSig route if element is in one since if any part of it is truncated the continuation exit will be removed - must
18395 // be so as continuation exit is at the end of the route, and truncation is from the end
18397  {
18399  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18400  AutoSigVectorIT--)
18401  {
18402  if(AutoSigVectorIT->RouteNumber == RequiredRoutePair.first)
18403  {
18404  TrainController->ContinuationAutoSigVector.erase(AutoSigVectorIT);
18405  }
18406  }
18407  }
18408 // now if last element from a route was removed need to remove the route from the route vector and from the LockedRouteVector if exists,
18409 // and adjust all the corresponding route numbers
18410  if(GetModifiableRouteAt(10, RequiredRoutePair.first).PrefDirSize() == 0)
18411  {
18412  TrainController->LogEvent("RouteRemoved," + AnsiString(GetFixedRouteAt(189, RequiredRoutePair.first).RouteID));
18413  AllRoutesVector.erase(AllRoutesVector.begin() + RequiredRoutePair.first);
18414  DecrementRouteNumbersInRoute2MultiMap(0, RequiredRoutePair.first);
18415 
18416 /* drop this: LockedVectorNumber was supposed to be determined from the above section that has been dropped, so this doesn't work
18417  It isn't needed anyway as a check is made after the Locked route timeout as to whether the end element is in a route or not, and if not
18418  it is erased then - see TInterface::ApproachLocking
18419 
18420  if(LockedVectorNumber > -1)
18421  {
18422  LockedRouteVector.erase(LockedRouteVector.begin() + LockedVectorNumber);
18423  }
18424 */
18425  // decrement route numbers in the locked route vector whether or not this route is a locked route
18426  if(!LockedRouteVector.empty())
18427  {
18428  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18429  {
18430  if(LRVIT->RouteNumber > RequiredRoutePair.first)
18431  {
18432  LRVIT->RouteNumber--;
18433  }
18434  }
18435  }
18437  {
18439  for(AutoSigVectorIT = TrainController->ContinuationAutoSigVector.end() - 1; AutoSigVectorIT >= TrainController->ContinuationAutoSigVector.begin();
18440  AutoSigVectorIT--)
18441  {
18442  if(AutoSigVectorIT->RouteNumber > RequiredRoutePair.first)
18443  {
18444  AutoSigVectorIT->RouteNumber--;
18445  }
18446  }
18447  }
18448  }
18449  CheckMapAndRoutes(7); // test
18450  Utilities->CallLogPop(407);
18451 }
18452 
18453 // ---------------------------------------------------------------------------
18454 
18455 void TAllRoutes::AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
18456 /*
18457  A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2MultiMap.
18458  Called from TAllRoutes::StoreOneRoute. Note that the IsARoute boolean variable is set in StoreRouteElementInPrefDirVector
18459  since that catches all route elements wherever created
18460 */
18461 {
18462  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",AddRouteElement," + AnsiString(HLoc) + "," + AnsiString(VLoc) + "," +
18463  AnsiString(ELink) + "," + AnsiString(RouteNumber) + "," + RouteElement.LogPrefDir());
18464  GetModifiableRouteAt(11, RouteNumber).StoreRouteElementInPrefDirVector(RouteElement);
18465  Route2MultiMapInsert(0, HLoc, VLoc, ELink, RouteNumber, GetModifiableRouteAt(12, RouteNumber).PrefDirSize() - 1);
18466  Utilities->CallLogPop(408);
18467 }
18468 
18469 // ---------------------------------------------------------------------------
18470 
18471 void TAllRoutes::SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
18472 /*
18473  Enter with signal at TrackVectorElement already set to red by the passing train.
18474  Identify the route that the TrackVectorPosition is in, carry out validity checks, then call SetAllRearwardsSignals to set signals
18475  in this route and all linked rearwards routes, unless find a train (a) in the current route, in which case the signals behind it are
18476  set (and behind any other trains in the current route), but only within the current route; or (b) in a linked rear route, in which
18477  case the function sets no further signals.
18478 */
18479 {
18480  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnAutoSigsRoute," + AnsiString(TrackVectorPosition) +
18481  "," + AnsiString(XLinkPos));
18482  TRouteElementPair RouteElementPair, SecondPair, RequiredPair;
18483  TTrackElement TE = Track->TrackElementAt(159, TrackVectorPosition);
18484 
18485  RouteElementPair = GetRouteElementDataFromRoute2MultiMap(9, TE.HLoc, TE.VLoc, SecondPair);
18486  if(RouteElementPair.first == -1)
18487  {
18488  throw Exception("Error, failed to find element in SetTrailingSignalsOnAutoSigsRoute - 1");
18489  }
18490  TPrefDirElement RouteElement = GetFixedRouteAt(119, RouteElementPair.first).GetFixedPrefDirElementAt(138, RouteElementPair.second);
18491 
18492  RequiredPair = RouteElementPair;
18493  if(RouteElement.XLinkPos != XLinkPos)
18494  {
18495  if(SecondPair.first != -1)
18496  {
18497  RouteElement = GetFixedRouteAt(120, SecondPair.first).GetFixedPrefDirElementAt(139, SecondPair.second);
18498  RequiredPair = SecondPair;
18499  if(RouteElement.XLinkPos != XLinkPos)
18500  {
18501  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 2");
18502  }
18503  }
18504  else
18505  {
18506  throw Exception("Failed to find element in route in SetTrailingSignalsOnAutoSigsRoute - 3");
18507  }
18508  }
18509 // new function
18510  SetAllRearwardsSignals(5, 0, RequiredPair.first, RequiredPair.second);
18511  Utilities->CallLogPop(409);
18512 }
18513 
18514 // ---------------------------------------------------------------------------
18515 
18516 void TAllRoutes::SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
18517 /*
18518  This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in TrainController to set signals on
18519  the AutoSigsRoute to correspond to a train having exited the route at a continuation, and passing further signals (outside the simulated
18520  railway). Initially the last passed signal will be red, then at the first call it will change to yellow and earlier signals will change
18521  accordingly, then double yellow, then green. There are only 3 calls in all for any given route, and the AccessNumber changes from 0 to 1
18522  to 2 for successive calls.
18523  Initially Attribute is set to AccessNumber + 1 to correspond to the first signal attribute to be set, then a number of validity checks
18524  are carried out on RouteNumber. Then SetAllRearwardsSignals is called to set signals in this route and all linked rearwards routes,
18525  unless find a train (a) in the current route, in which case the signals behind it are set (and behind any other trains in the current
18526  route), but only within the current route; or (b) in a linked rear route, in which case the function sets no further signals.
18527 */
18528 {
18529  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetTrailingSignalsOnContinuationRoute," + AnsiString(RouteNumber) + "," +
18530  AnsiString(AccessNumber));
18531  TPrefDirElement RouteElement;
18532  int Attribute = AccessNumber + 1;
18533 // signal attributes: 0=red; 1=yellow; 2=double yellow; 3 = green
18534  int x = GetFixedRouteAt(121, RouteNumber).PrefDirSize() - 1;
18535 
18536  if(!(GetFixedRouteAt(122, RouteNumber).GetFixedPrefDirElementAt(140, x).AutoSignals))
18537  {
18538  throw Exception("Error - route not AutoSignals in SetTrailingSignalsOnContinuationRoute");
18539  }
18540  if(GetFixedRouteAt(123, RouteNumber).GetFixedPrefDirElementAt(141, x).TrackType != Continuation)
18541  {
18542  throw Exception("Error - end element not continuation in SetTrailingSignalsOnContinuationRoute");
18543  }
18544  if(GetFixedRouteAt(124, RouteNumber).GetFixedPrefDirElementAt(142, x).Config[GetFixedRouteAt(125, RouteNumber).GetFixedPrefDirElementAt(143,
18545  x).XLinkPos] != End)
18546  {
18547  throw Exception("Error - end element a continuation in SetTrailingSignalsOnContinuationRoute but End not facing right way");
18548  }
18549 // new function
18550  SetAllRearwardsSignals(6, Attribute, RouteNumber, GetFixedRouteAt(126, RouteNumber).PrefDirSize() - 1);
18551  Utilities->CallLogPop(410);
18552 }
18553 
18554 // ---------------------------------------------------------------------------
18555 
18556 void TAllRoutes::SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
18557 /*
18558  Sets signals in all linked rearwards routes from the RouteStartPosition in RouteNumber, unless find a train (a) in the current route,
18559  in which case the signals behind it are set (and behind any other trains in the current route), but only within the current route;
18560  or (b) in a linked rear route, in which case the function sets no further signals.
18561 
18562  First call SetRearwardsSignalsReturnFalseForTrain (which is only called by this function) to set signals in route RouteNumber according
18563  to the received or modified (because of the forward look for buffers or continuation) Attribute. If no train is found during this call
18564  (returns true) then check for and call SetRearwardsSignalsReturnFalseForTrain for each rearwards linked route until either reach the
18565  beginning of the last linked route or find a train on a linked rear route. If no train was found during the RouteNumber call to
18566  SetRearwardsSignalsReturnFalseForTrain then the function terminates here.
18567  However if a train was found during the RouteNumber call to SetRearwardsSignalsReturnFalseForTrain then need to continue after the
18568  train in case had just added a route segment behind a train that now forms part of a single continuous route, otherwise the signals
18569  won't be set behind the train. First the route is examined element by element from the RouteStartPosition towards the start of the
18570  route until the train is found. Then the route elements are examined from the TrainPosition towards the start of the route until the
18571  first element behind the train is found. A recursive call to this function is then made from this behind-train position, to set all
18572  signals behind the train (and behind as many trains as there are on the single route) beginning with a red signal for the first signal
18573  found behind the train.
18574 
18575  Description of SetRearwardsSignalsReturnFalseForTrain for reference:
18576  Enter with Attribute set to the value to be used (unless modified by the initial forward search - see later) for the first rearwards
18577  signal found, and with PrefDirVectorStartPosition set to the position in PrefDirVector to begin the search. BUT, don't begin with the
18578  rearward search, first search forwards from the PrefDirVectorStartPosition in case the end of the route is a buffer or continuation, and
18579  modify the Attribute accordingly UNLESS (a) train present between PrefDirVectorStartPosition & end; (b) route in
18580  ContinuationAutoSigVector (i.e. train has exited the route at a continuation but it is still affecting the signals), or (c) truncating
18581  a route.
18582 
18583  Having received or modified Attribute as above, work backwards from the PrefDirVectorStartPosition until find a train - return false, or a
18584  signal. If find a signal set its Attribute to the current Attribute value up to a maximum of 3, and replot the signal as well as
18585  the required route and direction (if required) graphics, then increment Attribute up to a max. of 3 [addition at v2.9.2: if signal or element beyond
18586  it is in a locked route then set signal to red & change Attribute to 0 - this fault reported by Simon Banham 21/07/21 as an image]. and continue working backwards
18587  for the next signal (or train - return false as before) and so on. On completion Attribute is passed back from the function as a
18588  reference. If no train is found before the beginning of the route is reached the function returns true
18589 
18590 */
18591 {
18592  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SetAllRearwardsSignals," + AnsiString(Attribute) + "," +
18593  AnsiString(RouteNumber) + "," + AnsiString(RouteStartPosition));
18594  TPrefDirElement FirstElement = GetFixedRouteAt(127, RouteNumber).GetFixedPrefDirElementAt(144, 0);
18595  int RearwardLinkedRouteNumber;
18596 
18597  Track->LCFoundInRouteBuildingFlag = false; // only examined for the new route segment, not for linked routes
18598  if(GetFixedRouteAt(128, RouteNumber).SetRearwardsSignalsReturnFalseForTrain(1, Attribute, RouteStartPosition)) // updates Attribute to 1+ final
18599  // signal value in the route for use in further linked routes
18600  {
18601  if(FirstElement.Conn[FirstElement.ELinkPos] > -1) // GetRouteTypeAndNumber tests for this but check here to avoid call if == -1
18602  {
18603  while(GetRouteTypeAndNumber(6, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18604  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18605  {
18606  if(!(GetFixedRouteAt(129, RearwardLinkedRouteNumber).SetRearwardsSignalsReturnFalseForTrain(2, Attribute, AllRoutes->GetFixedRouteAt(130,
18607  RearwardLinkedRouteNumber).PrefDirSize() - 1)))
18608  {
18609  break;
18610  }
18611  // in above the RouteSettingFlag is set to false because this call is for routes that lie behind the route that is being set so don't want to
18612  // flash LCs on those routes
18613  FirstElement = AllRoutes->GetFixedRouteAt(131, RearwardLinkedRouteNumber).GetFixedPrefDirElementAt(145, 0);
18614  }
18615  }
18616  }
18617  else
18618  // found a train in the entry route before the beginning of the route, so need to continue after the train in case had just added a
18619  // route segment behind a train that now forms part of a single continuous route, otherwise the signals won't be set behind the train
18620  {
18621  int TrainID, TrainPosition, BehindTrainPosition;
18622  bool FoundTrain = false, BehindTrain = false;
18623  for(int x = RouteStartPosition; x >= 0; x--) // first step back from start position until find the train....
18624  {
18625  TPrefDirElement PrefDirElement = GetFixedRouteAt(132, RouteNumber).GetFixedPrefDirElementAt(146, x);
18626  TTrackElement TrackElement = Track->TrackElementAt(160, PrefDirElement.TrackVectorPosition);
18627  TrainID = TrackElement.TrainIDOnElement;
18628  if(TrackElement.TrackType == Bridge)
18629  {
18630  if(PrefDirElement.XLinkPos < 2)
18631  {
18632  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18633  }
18634  else
18635  {
18636  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18637  }
18638  }
18639  if(TrainID == -1)
18640  {
18641  continue;
18642  }
18643  else
18644  {
18645  FoundTrain = true;
18646  TrainPosition = x;
18647  break;
18648  }
18649  }
18650  if(FoundTrain && (TrainPosition > 1)) // if TrainPosition 1 or less then no route behind the train so can stop
18651  {
18652  for(int x = TrainPosition; x >= 0; x--) // then step back from that position until find element behind the train - ignore any
18653  {
18654  // signals that the train itself is straddling, need the first signal behind the train to be set to red, when the train passes
18655  // the signal it's straddling the rearwards signals will be reset again. Even if there are two or more trains adjacent still
18656  // need the element behind the rearmost train.
18657  TPrefDirElement PrefDirElement = GetFixedRouteAt(133, RouteNumber).GetFixedPrefDirElementAt(147, x);
18658  TTrackElement TrackElement = Track->TrackElementAt(161, PrefDirElement.TrackVectorPosition);
18659  TrainID = TrackElement.TrainIDOnElement;
18660  if(TrackElement.TrackType == Bridge)
18661  {
18662  if(PrefDirElement.XLinkPos < 2)
18663  {
18664  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18665  }
18666  else
18667  {
18668  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18669  }
18670  }
18671  if(TrainID != -1)
18672  {
18673  continue; // still on train
18674  }
18675  else
18676  {
18677  BehindTrain = true;
18678  BehindTrainPosition = x;
18679  break;
18680  }
18681  }
18682  if(BehindTrain) // then carry out a recursive rearward signal setting behind the train &
18683  // so on for as many trains as there are on the single route
18684  {
18685  SetAllRearwardsSignals(7, 0, RouteNumber, BehindTrainPosition); // false because can't set a route where there is a train
18686  // first signal behind train to be red
18687  }
18688  }
18689  }
18690  Utilities->CallLogPop(411);
18691 }
18692 
18693 // ---------------------------------------------------------------------------
18694 
18695 bool TAllRoutes::RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
18696 {
18697 /* Locked if a train moving in the direction of the route within 3 signals back from truncate point (on the route itself or any linked routes, or on the element
18698  immediately before the start of the route or linked route - this because train cancels route elements that it touches) unless
18699  first signal is red, then OK
18700 */
18701  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",RouteLockingRequired," + AnsiString(RouteNumber) + "," +
18702  AnsiString(RouteTruncatePosition));
18703  int SignalCount = 0, TrainID, RearwardLinkedRouteNumber, StartPosition = RouteTruncatePosition;
18704  TOneRoute CurrentRoute = GetFixedRouteAt(134, RouteNumber);
18705  TPrefDirElement PrefDirElement, FirstElement;
18706  TTrackElement TrackElement;
18707  bool ExamineRoute = true;
18708 
18709  while(ExamineRoute)
18710  {
18711  for(int x = StartPosition; x >= 0; x--) //work back along the route from the truncate point
18712  {
18713  PrefDirElement = CurrentRoute.GetFixedPrefDirElementAt(148, x);
18714  TrackElement = Track->TrackElementAt(162, PrefDirElement.TrackVectorPosition);
18715  TrainID = TrackElement.TrainIDOnElement;
18716  if(TrackElement.TrackType == Bridge)
18717  {
18718  if(PrefDirElement.XLinkPos < 2)
18719  {
18720  TrainID = TrackElement.TrainIDOnBridgeTrackPos01;
18721  }
18722  else
18723  {
18724  TrainID = TrackElement.TrainIDOnBridgeTrackPos23;
18725  }
18726  }
18727  if(TrainID > -1)
18728  {
18729  if(TrainController->TrainVectorAtIdent(36, TrainID).Stopped())
18730  {
18731  //any trains further back in route will be protected by the red signal behind the stopped train
18732  Utilities->CallLogPop(412);
18733  return(false);
18734  }
18735  //added at v2.4.2 for trains facing the wrong way & moving but haven't moved a half element yet so route still intact
18736  if(TrainController->TrainVectorAtIdent(49, TrainID).GetLeadElement() != PrefDirElement.TrackVectorPosition) //if it isn't then the train is facing the
18737  //other way & can cancel the route
18738  {
18739  Utilities->CallLogPop(2203);
18740  return(false);
18741  }
18742  Utilities->CallLogPop(1961); //otherwise need to lock the route as have found a train on the route (trains forward of the truncate point caught by
18743  return(true); //TrainOccupyingRoute which is outside this function but also causes route locking)
18744  }
18745  if(PrefDirElement.Config[PrefDirElement.XLinkPos] == Signal) // XLinkPos because signal has to be facing same direction as PrefDir to count
18746  {
18747  if(TrackElement.Attribute == 0)
18748  {
18749  Utilities->CallLogPop(413);
18750  return(false); // OK, red signal in front of a train
18751  }
18752  SignalCount++;
18753  if(SignalCount >= 3)
18754  {
18755  Utilities->CallLogPop(414);
18756  return(false);
18757  }
18758  }
18759  if(PrefDirElement.Config[PrefDirElement.ELinkPos] == End) // buffer or continuation & no train
18760  // ElinkPos because working back along PrefDir to beginning
18761  {
18762  Utilities->CallLogPop(415);
18763  return(false); // test - set to true to create a locked buffer-ended route, false for normal use
18764  }
18765  }
18766  //now look at linked rearwards routes
18767  FirstElement = CurrentRoute.GetFixedPrefDirElementAt(149, 0);
18768  StartPosition = CurrentRoute.PrefDirSize() - 1;
18769  if(GetRouteTypeAndNumber(7, FirstElement.Conn[FirstElement.ELinkPos], FirstElement.ConnLinkPos[FirstElement.ELinkPos],
18770  RearwardLinkedRouteNumber) != TAllRoutes::NoRoute)
18771  {
18772  CurrentRoute = GetFixedRouteAt(135, RearwardLinkedRouteNumber);
18773  ExamineRoute = true;
18774  StartPosition = GetFixedRouteAt(136, RearwardLinkedRouteNumber).PrefDirSize() - 1;
18775  }
18776  else
18777  {
18778  // here check for a train on the element immediately before the first route element
18779  TTrackElement PriorTrackElement = Track->TrackElementAt(489, FirstElement.Conn[FirstElement.ELinkPos]);
18780  TrainID = PriorTrackElement.TrainIDOnElement;
18781  if(PriorTrackElement.TrackType == Bridge)
18782  {
18783  if(FirstElement.ConnLinkPos[FirstElement.ELinkPos] < 2)
18784  {
18785  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos01;
18786  }
18787  else
18788  {
18789  TrainID = PriorTrackElement.TrainIDOnBridgeTrackPos23;
18790  }
18791  }
18792  if(TrainID > -1)
18793  {
18794  if(TrainController->TrainVectorAtIdent(37, TrainID).Stopped())
18795  {
18796  Utilities->CallLogPop(748);
18797  return(false);
18798  }
18799  //added at v2.4.2 for trains facing the wrong way on the prior element & moving but haven't moved a half element yet
18800  if(TrainController->TrainVectorAtIdent(50, TrainID).GetLeadElement() != FirstElement.Conn[FirstElement.ELinkPos]) //if it isn't then the train is facing the
18801  //other way & can cancel the route
18802  {
18803  Utilities->CallLogPop(2204);
18804  return(false);
18805  }
18806  Utilities->CallLogPop(1962);
18807  return(true); //otherwise need to lock the route
18808  }
18809  ExamineRoute = false;
18810  }
18811  }
18812 // if reach beginning of all rear routes without finding a train and there aren't 3 signals then truncate the route
18813 // as trains running on unrouted lines are already at risk of wrong points etc so no benefit locking the route
18814  Utilities->CallLogPop(416);
18815  return(false);
18816 }
18817 
18818 // ---------------------------------------------------------------------------
18819 
18820 bool TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos,
18821  TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
18822 {
18823  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber," +
18824  AnsiString(TrackVectorPosition) + "," + AnsiString(XLinkPos));
18825  TPrefDirElement InternalPrefDirElement; // blank element
18826 
18827  PrefDirElement = InternalPrefDirElement;
18828  if(LockedRouteVector.empty())
18829  {
18830  Utilities->CallLogPop(417);
18831  return(false);
18832  }
18833 // make sure at least one locked route record is still valid - train may have removed it, if last element still present locked route still exists,
18834 // even if some elements have been removed from the front by a train
18835  bool InLockedRoute = false;
18836 
18837  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18838  {
18839  if(TrackIsInARoute(14, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos))
18840  {
18841  // end of route can't be points, crossover or bridge so danger of route being on the other track of a 2-track element
18842  // doesn't arise)
18843  InLockedRoute = true;
18844  break;
18845  }
18846  }
18847  if(!InLockedRoute)
18848  {
18849  Utilities->CallLogPop(418);
18850  return(false);
18851  }
18852  int RouteNumber, VectorCount = 0;
18853  TRouteType RouteType;
18854 
18855  for(TLockedRouteVectorIterator LRVIT = LockedRouteVector.begin(); LRVIT < LockedRouteVector.end(); LRVIT++)
18856  {
18857  RouteType = GetRouteTypeAndNumber(8, LRVIT->LastTrackVectorPosition, LRVIT->LastXLinkPos, RouteNumber);
18858  if(RouteType == NoRoute)
18859  {
18860  continue;
18861  }
18862  if((GetFixedRouteAt(137, RouteNumber).GetFixedPrefDirElementAt(150, GetFixedRouteAt(138, RouteNumber).PrefDirSize() - 1).TrackVectorPosition != (int)
18863  LRVIT->LastTrackVectorPosition) || (GetFixedRouteAt(139, RouteNumber).GetFixedPrefDirElementAt(151,
18864  GetFixedRouteAt(140, RouteNumber).PrefDirSize() - 1).XLinkPos != LRVIT->LastXLinkPos))
18865  {
18866  throw Exception
18867  ("Error, last element in locked route doesn't correspond with last element in associated route in IsElementInLockedRouteGetPrefDirElement");
18868  }
18869  for(int x = GetFixedRouteAt(141, RouteNumber).PrefDirSize() - 1; x >= 0; x--)
18870  {
18871  InternalPrefDirElement = GetFixedRouteAt(142, RouteNumber).GetFixedPrefDirElementAt(152, x);
18872  if(InternalPrefDirElement.TrackVectorPosition != (int)LRVIT->TruncateTrackVectorPosition)
18873  {
18874  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18875  {
18876  PrefDirElement = InternalPrefDirElement;
18877  LockedVectorNumber = VectorCount;
18878  Utilities->CallLogPop(419);
18879  return(true);
18880  }
18881  }
18882  else if(InternalPrefDirElement.TrackVectorPosition == (int)LRVIT->TruncateTrackVectorPosition)
18883  {
18884  if((InternalPrefDirElement.TrackVectorPosition == TrackVectorPosition) && (InternalPrefDirElement.XLinkPos == XLinkPos))
18885  {
18886  PrefDirElement = InternalPrefDirElement;
18887  LockedVectorNumber = VectorCount;
18888  Utilities->CallLogPop(420);
18889  return(true);
18890  }
18891  else
18892  {
18893  break; // reached & tested LRVIT->TruncateTrackVectorPosition for a match so don't want to go any further for this route
18894  }
18895  }
18896  }
18897  VectorCount++;
18898  }
18899  Utilities->CallLogPop(421);
18900  return(false);
18901 }
18902 
18903 // ---------------------------------------------------------------------------
18904 
18906 {
18907  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetRouteVectorNumber," + AnsiString(RouteID.GetInt()));
18908  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18909  {
18910  if(GetFixedRouteAt(157, x).RouteID == RouteID.GetInt())
18911  {
18912  Utilities->CallLogPop(963);
18913  return(x);
18914  }
18915  }
18916  throw Exception("Error, failed to find RouteID in GetRouteVectorNumber for ID: " + AnsiString(RouteID.GetInt()));
18917 }
18918 
18919 // ---------------------------------------------------------------------------
18920 
18922 // added at v1.3.1 after an error was generated when operating Ian Walker's Chiltern Railway
18923 // found to be due to a route having been removed by a train moving in the wrong direction after the route was selected but before it completed (i.e. route removed while flashing)
18924 {
18925  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",IsThereARouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18926  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18927  {
18928  if(GetFixedRouteAt(45, x).RouteID == RouteID.GetInt())
18929  {
18930  Utilities->CallLogPop(2039);
18931  return(true);
18932  }
18933  }
18934  Utilities->CallLogPop(2040);
18935  return(false);
18936 }
18937 
18938 // ---------------------------------------------------------------------------
18939 
18941 {
18942  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetFixedRouteAtIDNumber," + AnsiString(RouteID.GetInt()));
18943  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18944  {
18945  if(GetFixedRouteAt(163, x).RouteID == RouteID.GetInt())
18946  {
18947  Utilities->CallLogPop(964);
18948  return(GetFixedRouteAt(159, x));
18949  }
18950  }
18951  throw Exception("Error, failed to find RouteID in GetFixedRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18952 }
18953 
18954 // ---------------------------------------------------------------------------
18955 
18957 {
18958  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",GetModifiableRouteATIDNumber," + AnsiString(RouteID.GetInt()));
18959  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18960  {
18961  if(GetFixedRouteAt(164, x).RouteID == RouteID.GetInt())
18962  {
18963  Utilities->CallLogPop(965);
18964  return(GetModifiableRouteAt(15, x));
18965  }
18966  }
18967  throw Exception("Error, failed to find RouteID in GetModifiableRouteAtIDNumber for ID: " + AnsiString(RouteID.GetInt()));
18968 }
18969 
18970 // ---------------------------------------------------------------------------
18971 
18972 void TAllRoutes::SaveRoutes(int Caller, std::ofstream &OutFile)
18973 {
18974  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",SaveRoutes");
18975  Utilities->SaveFileInt(OutFile, AllRoutesSize()); // so know how many to reload
18976  Utilities->SaveFileInt(OutFile, NextRouteID);
18977  for(unsigned int x = 0; x < AllRoutesSize(); x++)
18978  {
18979  TOneRoute OneRoute = GetFixedRouteAt(165, x);
18980  Utilities->SaveFileInt(OutFile, OneRoute.RouteID);
18981  OneRoute.SavePrefDirVector(6, OutFile);
18982  }
18983  Utilities->CallLogPop(1442);
18984 }
18985 
18986 // ---------------------------------------------------------------------------
18987 
18988 bool TAllRoutes::LoadRoutes(int Caller, std::ifstream &InFile)
18989 {
18990  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",LoadRoutes");
18991  int NumberOfRoutes;
18992 
18993  NumberOfRoutes = Utilities->LoadFileInt(InFile);
18994  NextRouteID = Utilities->LoadFileInt(InFile);
18995  for(int x = 0; x < NumberOfRoutes; x++)
18996  {
18997  TOneRoute OneRoute; // empty route
18998  OneRoute.RouteID = Utilities->LoadFileInt(InFile);
18999  OneRoute.LoadPrefDir(2, InFile);
19001  {
19002  StoreOneRouteAfterSessionLoad(0, &OneRoute);
19003  }
19004  else
19005  {
19006  Utilities->CallLogPop(1443);
19007  return(false);
19008  }
19009  }
19010  Utilities->CallLogPop(1444);
19011  return(true);
19012 }
19013 
19014 // ---------------------------------------------------------------------------
19015 bool TAllRoutes::CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
19016 {
19017  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckRoutes," + AnsiString(NumberOfActiveElements));
19018  int NumberOfRoutes = Utilities->LoadFileInt(InFile);
19019 
19020  if((NumberOfRoutes < 0) || (NumberOfRoutes > 5000))
19021  {
19022  Utilities->CallLogPop(1445);
19023  return(false);
19024  }
19025  int NextID = Utilities->LoadFileInt(InFile);
19026 
19027  if((NextID < 0) || (NextID > 1000000))
19028  {
19029  Utilities->CallLogPop(1446);
19030  return(false);
19031  }
19032  for(int x = 0; x < NumberOfRoutes; x++)
19033  {
19034  int RouteID = Utilities->LoadFileInt(InFile);
19035  if((RouteID < 0) || (RouteID > 20000))
19036  {
19037  Utilities->CallLogPop(1447);
19038  return(false);
19039  }
19040  TOneRoute OneRoute; // create an empty route so CheckOnePrefDir can be called
19041  if(!(OneRoute.CheckOnePrefDir(3, NumberOfActiveElements, InFile)))
19042  {
19043  Utilities->CallLogPop(1448);
19044  return(false);
19045  }
19046  }
19047  Utilities->CallLogPop(1449);
19048  return(true);
19049 }
19050 
19051 // ---------------------------------------------------------------------------
19052 
19053 bool TAllRoutes::CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
19054 {
19055  // return true for a loop
19056  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",CheckForLoopingRoute," + AnsiString(EndPosition) + "," +
19057  AnsiString(StartPosition));
19058  if(EndPosition == StartPosition)
19059  {
19060  Utilities->CallLogPop(1839);
19061  return(true); // shouldn't happen but treat as a loop if does
19062  }
19063 // begin at EndPosition & EndXLinkPos & work forwards until reach end of route (return false) or StartElement (return true)
19064  int TVPos = EndPosition; //TVPos is the current element and NewTVPos is the element it connects to
19065  int LkPos = EndXLinkPos; //LkPos is the exit link and NewLkPos is the entry link of the linked element
19066 
19067  while(TrackIsInARoute(15, TVPos, LkPos))
19068  {
19069  int NewTVPos = Track->TrackElementAt(826, TVPos).Conn[LkPos]; //see above
19070  int NewLkPos = -1;
19071  if(NewTVPos > -1)
19072  {
19073  NewLkPos = Track->TrackElementAt(827, TVPos).ConnLinkPos[LkPos]; // this is the entry link pos
19074  if(NewLkPos == -1)
19075  {
19076  Utilities->CallLogPop(1840);
19077  return(true); // shouldn't arise but treat as loop if does
19078  }
19079  }
19080  else // reached a buffer or continuation
19081  {
19082  Utilities->CallLogPop(1841);
19083  return(false);
19084  }
19085 //Error found by Xeon notified by email 13/10/20.
19086 //Need to make sure there is a route with the new entry link NewLkPos on the next element (TrackIsInARoute normally used where it doesn't matter which track a route
19087 //is on - except for bridges). But here a route can end at a trailing point leg or a crossover and if so it doesn't link to the route on the other track, and needs to
19088 //return false. Without the new check below the program gets stuck in an endless loop, which is the error that Xeon found.
19089 //If there isn't a route at all on the next element then it would return false at the next iteration so can return false here.
19090 //New check added for v2.6.0
19091 //Note: Could probably use GetRouteTypeAndNumber in place of TrackIsInARoute in the while statement above and dispense with this new check, but I prefer to keep mods as simple
19092 //as possible in case there are other unforeseen effects.
19093  int RouteNumber; //dummy, not used
19094  if(GetRouteTypeAndNumber(36, NewTVPos, NewLkPos, RouteNumber) == NoRoute)
19095  {
19096  Utilities->CallLogPop(2241);
19097  return(false);
19098  }
19099  //now make the connected element the current element, read across the TV number and determine the exit link
19100  TVPos = NewTVPos;
19101  if(Track->TrackElementAt(828, TVPos).TrackType == Points)
19102  {
19103  if((NewLkPos == 0) || (NewLkPos == 2)) // leading points
19104  {
19105  if(Track->TrackElementAt(829, TVPos).Attribute == 0)
19106  {
19107  LkPos = 1;
19108  }
19109  else
19110  {
19111  LkPos = 3;
19112  }
19113  }
19114  else
19115  {
19116  LkPos = 0;
19117  }
19118  }
19119  else
19120  {
19121  LkPos = Track->GetNonPointsOppositeLinkPos(NewLkPos);
19122  }
19123  if(TVPos == StartPosition)
19124  {
19125  Utilities->CallLogPop(1842);
19126  return(true); // it is a loop
19127  }
19128  }
19129  Utilities->CallLogPop(1843);
19130  return(false); // reached end of route so not a loop
19131 }
19132 
19133 // ---------------------------------------------------------------------------
19134 
19135 bool TAllRoutes::DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19136 /*
19137  Track geometry allows diagonals to cross without occupying the same track element, so when
19138  route plotting it is necessary to check if there is an existing route or a train on such a crossing
19139  diagonal. Returns true for a fouled diagonal. Enter with H & V set for the element whose diagonal
19140  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19141  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19142  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19143  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19144  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19145  Each of these is examined in turn for each route element in the relevant position.
19146 
19147  NOTE: Originally this failed to detect a train fouling a diagonal. v1.2.0 checks for a train present on a
19148  crossing diagonal element using a new bool function TTrack::TrainOnLink(int HLoc, int VLoc, int Link)
19149  that returns false in all cases (including elements & links not present) except train present.
19150 */
19151 {
19152  int TrainID; // not used in this function
19153 
19154  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRouteOrTrain," + AnsiString(HLoc) + "," +
19155  AnsiString(VLoc) + "," + AnsiString(DiagonalLinkNumber));
19156  TPrefDirElement TempPrefDirElement;
19157  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19158 
19159  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(4, HLoc - 1, VLoc, SecondPair);
19160  if(FirstPair.first > -1)
19161  {
19162  TempPrefDirElement = AllRoutes->GetFixedRouteAt(50, FirstPair.first).GetFixedPrefDirElementAt(70, FirstPair.second);
19163  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19164  {
19165  Utilities->CallLogPop(310);
19166  return(true);
19167  }
19168  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19169  {
19170  Utilities->CallLogPop(311);
19171  return(true);
19172  }
19173  }
19174  if(SecondPair.first > -1)
19175  {
19176  TempPrefDirElement = AllRoutes->GetFixedRouteAt(51, SecondPair.first).GetFixedPrefDirElementAt(71, SecondPair.second);
19177  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19178  {
19179  Utilities->CallLogPop(312);
19180  return(true);
19181  }
19182  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19183  {
19184  Utilities->CallLogPop(313);
19185  return(true);
19186  }
19187  }
19188  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(0, HLoc - 1, VLoc, 3, TrainID)) || ((DiagonalLinkNumber == 7) && Track->TrainOnLink(1, HLoc - 1, VLoc,
19189  9, TrainID)))
19190  {
19191  Utilities->CallLogPop(1997);
19192  return(true);
19193  }
19194  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(5, HLoc, VLoc - 1, SecondPair);
19195  if(FirstPair.first > -1)
19196  {
19197  TempPrefDirElement = AllRoutes->GetFixedRouteAt(52, FirstPair.first).GetFixedPrefDirElementAt(72, FirstPair.second);
19198  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19199  {
19200  Utilities->CallLogPop(314);
19201  return(true);
19202  }
19203  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19204  {
19205  Utilities->CallLogPop(315);
19206  return(true);
19207  }
19208  }
19209  if(SecondPair.first > -1)
19210  {
19211  TempPrefDirElement = AllRoutes->GetFixedRouteAt(53, SecondPair.first).GetFixedPrefDirElementAt(73, SecondPair.second);
19212  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19213  {
19214  Utilities->CallLogPop(316);
19215  return(true);
19216  }
19217  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19218  {
19219  Utilities->CallLogPop(317);
19220  return(true);
19221  }
19222  }
19223  if(((DiagonalLinkNumber == 1) && Track->TrainOnLink(2, HLoc, VLoc - 1, 7, TrainID)) || ((DiagonalLinkNumber == 3) && Track->TrainOnLink(3, HLoc, VLoc - 1,
19224  9, TrainID)))
19225  {
19226  Utilities->CallLogPop(1998);
19227  return(true);
19228  }
19229  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(6, HLoc + 1, VLoc, SecondPair);
19230  if(FirstPair.first > -1)
19231  {
19232  TempPrefDirElement = AllRoutes->GetFixedRouteAt(54, FirstPair.first).GetFixedPrefDirElementAt(74, FirstPair.second);
19233  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19234  {
19235  Utilities->CallLogPop(318);
19236  return(true);
19237  }
19238  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19239  {
19240  Utilities->CallLogPop(319);
19241  return(true);
19242  }
19243  }
19244  if(SecondPair.first > -1)
19245  {
19246  TempPrefDirElement = AllRoutes->GetFixedRouteAt(55, SecondPair.first).GetFixedPrefDirElementAt(75, SecondPair.second);
19247  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19248  {
19249  Utilities->CallLogPop(320);
19250  return(true);
19251  }
19252  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19253  {
19254  Utilities->CallLogPop(321);
19255  return(true);
19256  }
19257  }
19258  if(((DiagonalLinkNumber == 3) && Track->TrainOnLink(4, HLoc + 1, VLoc, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(5, HLoc + 1, VLoc,
19259  7, TrainID)))
19260  {
19261  Utilities->CallLogPop(1999);
19262  return(true);
19263  }
19264  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(7, HLoc, VLoc + 1, SecondPair);
19265  if(FirstPair.first > -1)
19266  {
19267  TempPrefDirElement = AllRoutes->GetFixedRouteAt(56, FirstPair.first).GetFixedPrefDirElementAt(76, FirstPair.second);
19268  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19269  {
19270  Utilities->CallLogPop(322);
19271  return(true);
19272  }
19273  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19274  {
19275  Utilities->CallLogPop(323);
19276  return(true);
19277  }
19278  }
19279  if(SecondPair.first > -1)
19280  {
19281  TempPrefDirElement = AllRoutes->GetFixedRouteAt(57, SecondPair.first).GetFixedPrefDirElementAt(77, SecondPair.second);
19282  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19283  {
19284  Utilities->CallLogPop(324);
19285  return(true);
19286  }
19287  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19288  {
19289  Utilities->CallLogPop(325);
19290  return(true);
19291  }
19292  }
19293  if(((DiagonalLinkNumber == 7) && Track->TrainOnLink(6, HLoc, VLoc + 1, 1, TrainID)) || ((DiagonalLinkNumber == 9) && Track->TrainOnLink(7, HLoc, VLoc + 1,
19294  3, TrainID)))
19295  {
19296  Utilities->CallLogPop(2000);
19297  return(true);
19298  }
19299  Utilities->CallLogPop(326);
19300  return(false);
19301 }
19302 
19303 // ---------------------------------------------------------------------------
19304 
19305 bool TAllRoutes::DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
19306 /*
19307  As above but checks for a route only (may or may not be a train). Enter with H & V set for the element whose diagonal
19308  is to be checked, and the XLink number of the relevant diagonal, which must be 1, 3, 7 or 9.
19309  for XLink = 1, potentially fouled diagonals are at H-1, V, Lk 3 & H, V-1, Lk 7
19310  for XLink = 3, potentially fouled diagonals are at H+1, V, Lk 1 & H, V-1 Lk 9
19311  for XLink = 7, potentially fouled diagonals are at H-1, V, Lk 9 & H, V+1 Lk 1
19312  for XLink = 9, potentially fouled diagonals are at H+1, V, Lk 7 & H, V+1 Lk 3
19313  Each of these is examined in turn for each route element in the relevant position.
19314 */
19315 {
19316  Utilities->CallLog.push_back(Utilities->TimeStamp() + "," + AnsiString(Caller) + ",DiagonalFouledByRoute," + AnsiString(HLoc) + "," + AnsiString(VLoc) +
19317  "," + AnsiString(DiagonalLinkNumber));
19318  TPrefDirElement TempPrefDirElement;
19319  TAllRoutes::TRouteElementPair FirstPair, SecondPair;
19320 
19321  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(17, HLoc - 1, VLoc, SecondPair);
19322  if(FirstPair.first > -1)
19323  {
19324  TempPrefDirElement = AllRoutes->GetFixedRouteAt(197, FirstPair.first).GetFixedPrefDirElementAt(233, FirstPair.second);
19325  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19326  {
19327  Utilities->CallLogPop(2010);
19328  return(true);
19329  }
19330  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19331  {
19332  Utilities->CallLogPop(2011);
19333  return(true);
19334  }
19335  }
19336  if(SecondPair.first > -1)
19337  {
19338  TempPrefDirElement = AllRoutes->GetFixedRouteAt(198, SecondPair.first).GetFixedPrefDirElementAt(234, SecondPair.second);
19339  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19340  {
19341  Utilities->CallLogPop(2012);
19342  return(true);
19343  }
19344  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19345  {
19346  Utilities->CallLogPop(2013);
19347  return(true);
19348  }
19349  }
19350  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(18, HLoc, VLoc - 1, SecondPair);
19351  if(FirstPair.first > -1)
19352  {
19353  TempPrefDirElement = AllRoutes->GetFixedRouteAt(199, FirstPair.first).GetFixedPrefDirElementAt(235, FirstPair.second);
19354  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19355  {
19356  Utilities->CallLogPop(2014);
19357  return(true);
19358  }
19359  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19360  {
19361  Utilities->CallLogPop(2015);
19362  return(true);
19363  }
19364  }
19365  if(SecondPair.first > -1)
19366  {
19367  TempPrefDirElement = AllRoutes->GetFixedRouteAt(200, SecondPair.first).GetFixedPrefDirElementAt(236, SecondPair.second);
19368  if((DiagonalLinkNumber == 1) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19369  {
19370  Utilities->CallLogPop(2016);
19371  return(true);
19372  }
19373  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 9) || (TempPrefDirElement.XLink == 9)))
19374  {
19375  Utilities->CallLogPop(2017);
19376  return(true);
19377  }
19378  }
19379  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(19, HLoc + 1, VLoc, SecondPair);
19380  if(FirstPair.first > -1)
19381  {
19382  TempPrefDirElement = AllRoutes->GetFixedRouteAt(201, FirstPair.first).GetFixedPrefDirElementAt(237, FirstPair.second);
19383  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19384  {
19385  Utilities->CallLogPop(2018);
19386  return(true);
19387  }
19388  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19389  {
19390  Utilities->CallLogPop(2019);
19391  return(true);
19392  }
19393  }
19394  if(SecondPair.first > -1)
19395  {
19396  TempPrefDirElement = AllRoutes->GetFixedRouteAt(202, SecondPair.first).GetFixedPrefDirElementAt(238, SecondPair.second);
19397  if((DiagonalLinkNumber == 3) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19398  {
19399  Utilities->CallLogPop(2020);
19400  return(true);
19401  }
19402  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 7) || (TempPrefDirElement.XLink == 7)))
19403  {
19404  Utilities->CallLogPop(2021);
19405  return(true);
19406  }
19407  }
19408  FirstPair = AllRoutes->GetRouteElementDataFromRoute2MultiMap(20, HLoc, VLoc + 1, SecondPair);
19409  if(FirstPair.first > -1)
19410  {
19411  TempPrefDirElement = AllRoutes->GetFixedRouteAt(203, FirstPair.first).GetFixedPrefDirElementAt(239, FirstPair.second);
19412  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19413  {
19414  Utilities->CallLogPop(2022);
19415  return(true);
19416  }
19417  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19418  {
19419  Utilities->CallLogPop(2023);
19420  return(true);
19421  }
19422  }
19423  if(SecondPair.first > -1)
19424  {
19425  TempPrefDirElement = AllRoutes->GetFixedRouteAt(204, SecondPair.first).GetFixedPrefDirElementAt(240, SecondPair.second);
19426  if((DiagonalLinkNumber == 7) && ((TempPrefDirElement.ELink == 1) || (TempPrefDirElement.XLink == 1)))
19427  {
19428  Utilities->CallLogPop(2024);
19429  return(true);
19430  }
19431  if((DiagonalLinkNumber == 9) && ((TempPrefDirElement.ELink == 3) || (TempPrefDirElement.XLink == 3)))
19432  {
19433  Utilities->CallLogPop(2025);
19434  return(true);
19435  }
19436  }
19437  Utilities->CallLogPop(2026);
19438  return(false);
19439 }
19440 
19441 // ---------------------------------------------------------------------------
TTrain::LinkOccupied
bool LinkOccupied(int Caller, int TrackVectorPosition, int LinkNumber)
Added at v1.2.0: true if any part of train on specific link, false otherwise, including no link prese...
Definition: TrainUnit.cpp:8375
TRailGraphics::gl70
Graphics::TBitmap * gl70
Definition: GraphicUnit.h:677
TRailGraphics::bm72CallingOn
Graphics::TBitmap * bm72CallingOn
Definition: GraphicUnit.h:477
TAllRoutes::TrackIsInARoute
bool TrackIsInARoute(int Caller, int TrackVectorPosition, int LinkPos)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17550
TPrefDirRoute
TPrefDirRoute
< used in TOnePrefDir::PrefDirMarker to indicate whether the function is being called for a preferred...
Definition: TrackUnit.h:1296
TRailGraphics::sm120
Graphics::TBitmap * sm120
Definition: GraphicUnit.h:917
TRailGraphics::bm7
Graphics::TBitmap * bm7
Definition: GraphicUnit.h:464
TOnePrefDir::LastElementPtr
TPrefDirVectorIterator LastElementPtr(int Caller)
Return a pointer to the last element in the vector.
Definition: TrackUnit.cpp:11321
TRailGraphics::gl58
Graphics::TBitmap * gl58
Definition: GraphicUnit.h:663
TRailGraphics::LCLHSVerMan
Graphics::TBitmap * LCLHSVerMan
Definition: GraphicUnit.h:730
TUserGraphicItem::UserGraphic
TPicture * UserGraphic
Definition: DisplayUnit.h:36
TRailGraphics::gl145
Graphics::TBitmap * gl145
Definition: GraphicUnit.h:613
TRailGraphics::gl102
Graphics::TBitmap * gl102
Definition: GraphicUnit.h:565
TTrack::UserGraphicVectorAt
TUserGraphicItem & UserGraphicVectorAt(int Caller, int At)
A range-checked version of UserGraphicVector.at(At)
Definition: TrackUnit.cpp:11294
TGraphicElement::HPos
int HPos
Definition: TrackUnit.h:450
TTrack::GapVLoc
int GapVLoc
record gap setting info
Definition: TrackUnit.h:584
TTextItem::VPos
int VPos
the vertical position on the railway
Definition: TextUnit.h:50
TDisplay::DisplayOffsetHHome
static int DisplayOffsetHHome
the horizontal offset of the 'Home' display
Definition: DisplayUnit.h:80
TRailGraphics::bm11
Graphics::TBitmap * bm11
Definition: GraphicUnit.h:353
TRailGraphics::sm99
Graphics::TBitmap * sm99
Definition: GraphicUnit.h:875
TTrack::ResetGapsFromGapMap
bool ResetGapsFromGapMap(int Caller)
Called by RepositionAndMapTrack to reset the connecting elements of all set gaps (their TrackVector p...
Definition: TrackUnit.cpp:5457
TOnePrefDir::RebuildPrefDirVector
void RebuildPrefDirVector(int Caller)
Called after the track vector has been rebuilt following linking, to rebuild the preferred direction ...
Definition: TrackUnit.cpp:12840
TRailGraphics::sm129
Graphics::TBitmap * sm129
Definition: GraphicUnit.h:772
TFixedTrackPiece
Definition: TrackUnit.h:84
TFixedTrackPiece::PlotFixedTrackElement
void PlotFixedTrackElement(int Caller, int HLocInput, int VLocInput) const
Plot the element on the railway display at position HLocInput & VLocInput.
Definition: TrackUnit.cpp:127
TAllRoutes::LockedRouteVector
TLockedRouteVector LockedRouteVector
the vector that stores all the locked routes on the railway
Definition: TrackUnit.h:1702
TUtilities::LoadFileString
AnsiString LoadFileString(std::ifstream &InFile)
loads a string value from the file
Definition: Utilities.cpp:190
TTrack::LNDone2MultiMap
TLNDone2MultiMap LNDone2MultiMap
multimap of processed location name elements (see type for more information above)
Definition: TrackUnit.h:804
TTextHandler::RebuildFromTextVector
void RebuildFromTextVector(int Caller, TDisplay *Disp)
display all text items in TextVector on the screen
Definition: TextUnit.cpp:425
TRailGraphics::sm72
Graphics::TBitmap * sm72
Definition: GraphicUnit.h:908
TAllRoutes::Route2MultiMapInsert
void Route2MultiMapInsert(int Caller, int HLoc, int VLoc, int ELinkIn, int RouteNumber, unsigned int RouteElementNumber)
Insert an entry in Route2MultiMap. Called by TAllRoutes::AddRouteElement.
Definition: TrackUnit.cpp:18146
TFixedTrackPiece::GraphicPtr
Graphics::TBitmap * GraphicPtr
the track bitmap for display on the zoomed-in railway
Definition: TrackUnit.h:93
TRailGraphics::sm2
Graphics::TBitmap * sm2
Definition: GraphicUnit.h:791
clB5G0R0
#define clB5G0R0
Definition: GraphicUnit.h:246
TRailGraphics::sm73
Graphics::TBitmap * sm73
Definition: GraphicUnit.h:909
TTrack::IsNamedNonStationLocationPresent
bool IsNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location at HLoc & VLoc.
Definition: TrackUnit.cpp:9882
TRailGraphics::sm21
Graphics::TBitmap * sm21
Definition: GraphicUnit.h:793
TAllRoutes::SetAllRearwardsSignals
void SetAllRearwardsSignals(int Caller, int Attribute, int RouteNumber, int RouteStartPosition)
Set rearwards signals from the specified route starting position.
Definition: TrackUnit.cpp:18556
TRailGraphics::sm123
Graphics::TBitmap * sm123
Definition: GraphicUnit.h:920
TOnePrefDir::SearchLimitLowV
int SearchLimitLowV
Definition: TrackUnit.h:1350
TRailGraphics::bm8
Graphics::TBitmap * bm8
Definition: GraphicUnit.h:509
TTrack::GapMap
TGapMap GapMap
map of gaps (see type for more information above)
Definition: TrackUnit.h:796
TRailGraphics::gl117
Graphics::TBitmap * gl117
Definition: GraphicUnit.h:581
TRailGraphics::gl89set
Graphics::TBitmap * gl89set
Definition: GraphicUnit.h:702
TOnePrefDir::ErasePrefDirElementAt
void ErasePrefDirElementAt(int Caller, int PrefDirVectorPosition)
Erase a single element from PrefDirVector and 4MultiMap, decrementing the remaining PrefDirElementNum...
Definition: TrackUnit.cpp:13261
TRailGraphics::sm104
Graphics::TBitmap * sm104
Definition: GraphicUnit.h:759
TRailGraphics::gl19
Graphics::TBitmap * gl19
Definition: GraphicUnit.h:620
TTrack::UserGraphicMap
TUserGraphicMap UserGraphicMap
the map of graphic filenames as key and TPicture* as values
Definition: TrackUnit.h:811
TGraphicElement::ScreenSourceSet
bool ScreenSourceSet
Definition: TrackUnit.h:448
TOnePrefDir::CheckPrefDirAgainstTrackVector
void CheckPrefDirAgainstTrackVector(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found give message & clear EveryPrefD...
Definition: TrackUnit.cpp:12880
TRailGraphics::gl72
Graphics::TBitmap * gl72
Definition: GraphicUnit.h:679
TRailGraphics::ChangeAllTransparentColours
void ChangeAllTransparentColours(TColor NewTransparentColour, TColor OldTransparentColour)
Definition: GraphicUnit.cpp:3625
TRailGraphics::gl88set
Graphics::TBitmap * gl88set
Definition: GraphicUnit.h:700
TRailGraphics::bm28
Graphics::TBitmap * bm28
Definition: GraphicUnit.h:395
TRailGraphics::bm68grounddblred
Graphics::TBitmap * bm68grounddblred
Definition: GraphicUnit.h:454
TRailGraphics::smLC
Graphics::TBitmap * smLC
Definition: GraphicUnit.h:881
TTrack::BarriersDownVector
TActiveLCVector BarriersDownVector
vector of LCs with barriers down
Definition: TrackUnit.h:794
TPrefDirElement::GetXLinkPos
int GetXLinkPos() const
Returns the XLink array position.
Definition: TrackUnit.h:299
TTrack::IsLCBarrierDownAtHV
bool IsLCBarrierDownAtHV(int Caller, int HLoc, int VLoc)
True if an open (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7137
TAllRoutes::TLockedRouteClass::TruncateTrackVectorPosition
unsigned int TruncateTrackVectorPosition
the TrackVector position of the element selected for truncation
Definition: TrackUnit.h:1619
TOneRoute::GetRouteTruncateElement
void GetRouteTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute, TTruncateReturnType &ReturnFlag)
Examines the route to see whether the element at H & V is in the route, and if not returns a ReturnFl...
Definition: TrackUnit.cpp:17062
TRailGraphics::bm70grounddblred
Graphics::TBitmap * bm70grounddblred
Definition: GraphicUnit.h:467
TUtilities::ScreenElementWidth
int ScreenElementWidth
width of display screen in elements
Definition: Utilities.h:48
TRailGraphics::gl75
Graphics::TBitmap * gl75
Definition: GraphicUnit.h:684
TAllRoutes::LockedRouteLockStartTime
TDateTime LockedRouteLockStartTime
Definition: TrackUnit.h:1682
TTrack::TSigElement::Attribute
int Attribute
the signal state - red, yellow, double yellow or green
Definition: TrackUnit.h:728
TTrack::GetVectorPositionFromTrackMap
int GetVectorPositionFromTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Returns the track vector position corresponding to the Hloc & VLoc positions, FoundFlag indicates whe...
Definition: TrackUnit.cpp:5609
TTrack::PlotLCBaseElementsOnly
void PlotLCBaseElementsOnly(int Caller, TBarrierState State, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp)
Just replot the basic track elements at a level crossing (for flashing)
Definition: TrackUnit.cpp:7038
TTrack::GetTrackElementFromTrackMap
TTrackElement & GetTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5636
TOneRoute::TRouteFlash::OverlayPlotted
bool OverlayPlotted
flag indicating the graphic that is currently displayed, true for the overlay (route-coloured)
Definition: TrackUnit.h:1504
TTrack::LeftPlatAllowed
Set< int, 1, 146 > LeftPlatAllowed
Definition: TrackUnit.h:604
TAllRoutes::TRouteElementPair
std::pair< int, unsigned int > TRouteElementPair
defines a specific element in a route, the first (int) value is the vector position in the AllRoutesV...
Definition: TrackUnit.h:1643
NamedNonStationLocation
@ NamedNonStationLocation
Definition: TrackUnit.h:68
TRailGraphics::sm51
Graphics::TBitmap * sm51
Definition: GraphicUnit.h:826
TRailGraphics::sm77
Graphics::TBitmap * sm77
Definition: GraphicUnit.h:847
TTrack::NoActiveTrack
bool NoActiveTrack(int Caller)
True if there is no active track in the railway.
Definition: TrackUnit.cpp:1908
TPrefDirElement::GetRouteAutoSigsGraphicPtr
Graphics::TBitmap * GetRouteAutoSigsGraphicPtr()
picks up the blue route graphic (not used - superseded by GetRouteGraphicPtr)
Definition: TrackUnit.cpp:914
TTrack::CalcHLocMinEtc
void CalcHLocMinEtc(int Caller)
Examine TrackVector, InactiveTrackVector and TextVector, and set the values that indicate the extent ...
Definition: TrackUnit.cpp:10216
TTrack::TActiveLevelCrossing::ReducedTimePenalty
bool ReducedTimePenalty
marker that is set when a train is present on one of the elements of the LC - used to provide a 3 min...
Definition: TrackUnit.h:634
TOneRoute::FindForwardTargetSignalAttribute
bool FindForwardTargetSignalAttribute(int Caller, int &NextForwardLinkedRouteNumber, int &Attribute) const
Used when setting signal aspects for a route by working forwards through the route to see what the ne...
Definition: TrackUnit.cpp:16812
TRailGraphics::gl143
Graphics::TBitmap * gl143
Definition: GraphicUnit.h:612
TRailGraphics::sm70
Graphics::TBitmap * sm70
Definition: GraphicUnit.h:906
TAllRoutes::DiagonalFouledByRoute
bool DiagonalFouledByRoute(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
As above but only checks for a route (may or may not be a train present (new at v1....
Definition: TrackUnit.cpp:19305
TGraphicElement::VPos
int VPos
horizontal and vertical positions
Definition: TrackUnit.h:450
TAllRoutes::LockedRouteFoundDuringRouteBuilding
bool LockedRouteFoundDuringRouteBuilding
this flags the fact that a locked route has been found during route building in an existing linked ro...
Definition: TrackUnit.h:1673
TTextHandler::TextVector
TTextVector TextVector
Definition: TextUnit.h:69
TTrack::Lowering
@ Lowering
Definition: TrackUnit.h:625
TTrack::FindNonPlatformMatch
bool FindNonPlatformMatch(int Caller, int HLoc, int VLoc, int &Position, TTrackElement &TrackElement)
True if find a non-platform element at HLoc & VLoc, and if so return its TrackVector position and a r...
Definition: TrackUnit.cpp:2804
TRailGraphics::bm73CallingOn
Graphics::TBitmap * bm73CallingOn
Definition: GraphicUnit.h:484
TTrack::TFixedTrackArray::FixedTrackPiece
TFixedTrackPiece FixedTrackPiece[FirstUnusedSpeedTagNumber]
the array member
Definition: TrackUnit.h:569
TTrack::MatchingPoint
bool MatchingPoint(int Caller, unsigned int TrackVectorPosition, unsigned int DivergingPosition)
Definition: TrackUnit.cpp:5789
TRailGraphics::LCBotHorMan
Graphics::TBitmap * LCBotHorMan
Definition: GraphicUnit.h:728
TRailGraphics::gl66
Graphics::TBitmap * gl66
Definition: GraphicUnit.h:672
TRailGraphics::bm69grounddblred
Graphics::TBitmap * bm69grounddblred
Definition: GraphicUnit.h:460
TTrackElement::StationEntryStopLinkPos2
int StationEntryStopLinkPos2
Used for track at platforms and non-station named locations to mark the train front element stop posi...
Definition: TrackUnit.h:152
TTrack::EnterLocationName
void EnterLocationName(int Caller, AnsiString LocationName, bool AddingElements)
All platform, concourse, footcrossing & non-station named location elements are able to have a Locati...
Definition: TrackUnit.cpp:8056
TOneRoute::RouteSearchLimit
static const int RouteSearchLimit
limit to the number of elements searched in attempting to find a route
Definition: TrackUnit.h:1514
TUtilities::CheckFileStringZeroDelimiter
bool CheckFileStringZeroDelimiter(std::ifstream &InFile)
checks that the value is a string ('0' only accepted as the delimiter), returns true for success
Definition: Utilities.cpp:435
TTrack::TTrackVectorIterator
std::vector< TTrackElement >::iterator TTrackVectorIterator
iterator for TTrackVector
Definition: TrackUnit.h:663
TAllRoutes::ClearRouteDuringRouteBuildingAt
void ClearRouteDuringRouteBuildingAt(int Caller, int RouteNumber)
When attaching a new route section to an existing route, it is sometimes necessary to erase the origi...
Definition: TrackUnit.cpp:17984
TRailGraphics::sm108
Graphics::TBitmap * sm108
Definition: GraphicUnit.h:763
TTrack::Tag79Array
int Tag79Array[25][3]
Definition: TrackUnit.h:596
TRailGraphics::gl60
Graphics::TBitmap * gl60
Definition: GraphicUnit.h:666
TOnePrefDir::SavePrefDirVector
void SavePrefDirVector(int Caller, std::ofstream &VecFile)
Save the preferred direction vector to a file.
Definition: TrackUnit.cpp:12619
TRailGraphics::bm132
Graphics::TBitmap * bm132
Definition: GraphicUnit.h:360
TTrack::GetTrackLocsFromScreenPos
void GetTrackLocsFromScreenPos(int Caller, int &HLoc, int &VLoc, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos except that in this function HLoc & VLoc are expressed in t...
Definition: TrackUnit.cpp:7523
TRailGraphics::bm73
Graphics::TBitmap * bm73
Definition: GraphicUnit.h:483
TRailGraphics::bm30
Graphics::TBitmap * bm30
Definition: GraphicUnit.h:401
TTrainController::TrainVectorAtIdent
TTrain & TrainVectorAtIdent(int Caller, int TrainID)
Return a reference to the train with ID TrainID, carries out validity checking on TrainID.
Definition: TrainUnit.cpp:9441
TTrack::DecrementValuesInGapsAndTrackAndNameMaps
void DecrementValuesInGapsAndTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the TrackVector, all the later elements are moved down one....
Definition: TrackUnit.cpp:9260
TOnePrefDir::GetStartAndEndPrefDirElements
bool GetStartAndEndPrefDirElements(int Caller, TPrefDirElement &StartElement, TPrefDirElement &EndElement, int &LastIteratorValue)
Called when searching for start and end PrefDirElements when setting up automatic signals routes in P...
Definition: TrackUnit.cpp:13909
TTextItem::HPos
int HPos
the horizontal position on the railway
Definition: TextUnit.h:48
TTrainController::StopTTClockMessage
void StopTTClockMessage(int Caller, AnsiString Message)
sends a message to the user and stops the timetable clock while it is displayed
Definition: TrainUnit.cpp:14961
TRailGraphics::gl103
Graphics::TBitmap * gl103
Definition: GraphicUnit.h:566
TAllRoutes::GetAllRoutesTruncateElement
bool GetAllRoutesTruncateElement(int Caller, int HLoc, int VLoc, bool PrefDirRoute)
Examines all routes and for each uses GetRouteTruncateElement to see if the element at H & V is prese...
Definition: TrackUnit.cpp:17510
TAllRoutes::RemoveRouteElement
void RemoveRouteElement(int Caller, int HLoc, int VLoc, int ELink)
Erases the route element from Route2MultiMap and from the PrefDirVector.
Definition: TrackUnit.cpp:18346
TRailGraphics::sm83
Graphics::TBitmap * sm83
Definition: GraphicUnit.h:857
TTrack::NoPlatsMessageSent
bool NoPlatsMessageSent
used to send no platforms warning once only
Definition: TrackUnit.h:757
TRailGraphics::sm81
Graphics::TBitmap * sm81
Definition: GraphicUnit.h:855
TRailGraphics::bm74grounddblwhite
Graphics::TBitmap * bm74grounddblwhite
Definition: GraphicUnit.h:494
TAllRoutes::TLockedRouteClass::LastXLinkPos
int LastXLinkPos
the XLinkPos value of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1623
TRailGraphics::sm97
Graphics::TBitmap * sm97
Definition: GraphicUnit.h:873
TRailGraphics::Concourse
Graphics::TBitmap * Concourse
Definition: GraphicUnit.h:548
TOnePrefDir::LoadOldPrefDir
void LoadOldPrefDir(int Caller, std::ifstream &VecFile)
Old version of LoadPrefDir, used during development when the save format changed so the old files cou...
Definition: TrackUnit.cpp:12423
TTrackElement::FourAspect
@ FourAspect
Definition: TrackUnit.h:159
TRailGraphics::bm9
Graphics::TBitmap * bm9
Definition: GraphicUnit.h:513
TTrack::FindSetAndDisplayMatchingGap
bool FindSetAndDisplayMatchingGap(int Caller, int HLoc, int VLoc)
True if find an unset gap that matches the gap at HLoc & VLoc, if find one mark it with a green circl...
Definition: TrackUnit.cpp:4431
TTrack::CheckActiveLCVector
bool CheckActiveLCVector(int Caller, std::ifstream &VecFile)
Definition: TrackUnit.cpp:3642
TRailGraphics::gl67
Graphics::TBitmap * gl67
Definition: GraphicUnit.h:673
TRailGraphics::sm56
Graphics::TBitmap * sm56
Definition: GraphicUnit.h:831
TOneRoute::StartRoutePosition
int StartRoutePosition
TrackVectorPosition of the StartElement(s) set when the starting position of a new route is selected,...
Definition: TrackUnit.h:1526
TRailGraphics::bm69dblyellow
Graphics::TBitmap * bm69dblyellow
Definition: GraphicUnit.h:459
TRailGraphics::gl118
Graphics::TBitmap * gl118
Definition: GraphicUnit.h:582
TRailGraphics::sm105
Graphics::TBitmap * sm105
Definition: GraphicUnit.h:760
TRailGraphics::bm70dblyellow
Graphics::TBitmap * bm70dblyellow
Definition: GraphicUnit.h:466
TRailGraphics::sm24
Graphics::TBitmap * sm24
Definition: GraphicUnit.h:796
TTrack::CheckFootCrossingLinks
bool CheckFootCrossingLinks(int Caller, TTrackElement &TrackElement)
True if a footcrossing is linked properly at both ends.
Definition: TrackUnit.cpp:7871
TGraphicElement::SourceRect
TRect SourceRect
source rectangle of the original graphic
Definition: TrackUnit.h:456
TUtilities::LoadFileDouble
double LoadFileDouble(std::ifstream &InFile)
loads a double value from the file (converts from a string to a double) and uses the local decimal po...
Definition: Utilities.cpp:172
TRailGraphics::gl57
Graphics::TBitmap * gl57
Definition: GraphicUnit.h:662
TRailGraphics::gl120
Graphics::TBitmap * gl120
Definition: GraphicUnit.h:585
TPrefDirElement::GetDirectionRouteGraphicPtr
Graphics::TBitmap * GetDirectionRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute) const
picks up the green or red route direction graphic
Definition: TrackUnit.cpp:1026
TTrack::ShowSelectedGap
void ShowSelectedGap(int Caller, TDisplay *Disp)
Called during gap setting to mark a gap with a red circle - after which the program awaits user selec...
Definition: TrackUnit.cpp:4591
TOnePrefDir::TPrefDir4MultiMapEntry
std::pair< THVPair, unsigned int > TPrefDir4MultiMapEntry
Definition: TrackUnit.h:1310
TTrack::PlotLoweredLinkedLevelCrossingBarriers
void PlotLoweredLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, int TypeOfRoute, TDisplay *Disp, bool Manual)
Plot & open (to trains) all level crossings linked to TrackElement (Manual true = manually lowered,...
Definition: TrackUnit.cpp:6321
TTrack::OneNamedLocationElementAtLocation
bool OneNamedLocationElementAtLocation(int Caller, AnsiString LocationName)
True if there is at least one named location element with name 'LocationName', used in timetable inte...
Definition: TrackUnit.cpp:10705
TRailGraphics::gl5
Graphics::TBitmap * gl5
Definition: GraphicUnit.h:654
TRailGraphics::bm94unset
Graphics::TBitmap * bm94unset
Definition: GraphicUnit.h:517
TRailGraphics::sm93
Graphics::TBitmap * sm93
Definition: GraphicUnit.h:868
TTrack::CheckUserGraphics
bool CheckUserGraphics(int Caller, std::ifstream &InFile, UnicodeString GraphicsPath)
checks all user graphics & returns true for success
Definition: TrackUnit.cpp:3518
Unused
@ Unused
Definition: TrackUnit.h:67
TRailGraphics::gl122
Graphics::TBitmap * gl122
Definition: GraphicUnit.h:587
TRailGraphics::gl15
Graphics::TBitmap * gl15
Definition: GraphicUnit.h:617
TTrackElement::SigAspect
enum TTrackElement::@1 SigAspect
TOnePrefDir::TPrefDir4MultiMapIterator
std::multimap< THVPair, unsigned int, TMapComp >::iterator TPrefDir4MultiMapIterator
Definition: TrackUnit.h:1309
TRailGraphics::bm74
Graphics::TBitmap * bm74
Definition: GraphicUnit.h:490
TRailGraphics::gl90set
Graphics::TBitmap * gl90set
Definition: GraphicUnit.h:705
TAllRoutes::IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber
bool IsElementInLockedRouteGetPrefDirElementGetLockedVectorNumber(int Caller, int TrackVectorPosition, int XLinkPos, TPrefDirElement &PrefDirElement, int &LockedVectorNumber)
Checks whether the preferred direction element at TrackVectorPosition with XLinkPos value is in a loc...
Definition: TrackUnit.cpp:18820
TrackUnit.h
TTrack::ReturnNextInactiveTrackElement
bool ReturnNextInactiveTrackElement(int Caller, TTrackElement &Next)
Return a reference to the inactive track element pointed to by NextTrackElementPtr (during zoomed-in ...
Definition: TrackUnit.cpp:2837
TRailGraphics::sm117
Graphics::TBitmap * sm117
Definition: GraphicUnit.h:770
TPrefDirElement::IsARoute
bool IsARoute
false for Pref Dir, true for route
Definition: TrackUnit.h:240
TAllRoutes::CheckRoutes
bool CheckRoutes(int Caller, int NumberOfActiveElements, std::ifstream &InFile)
Performs an integrity check on the routes stored in a session file and returns false if there is an e...
Definition: TrackUnit.cpp:19015
TTrack::Tag76Array
int Tag76Array[25][3]
these arrays give valid adjacent named element relative positions for each type of named element,...
Definition: TrackUnit.h:592
TTrack::LengthMarker
void LengthMarker(int Caller, TDisplay *Disp)
Examine all elements in the TrackVector and if have a valid length mark the relevant track using Mark...
Definition: TrackUnit.cpp:9427
TAllRoutes::LockedRouteLastTrackVectorPosition
unsigned int LockedRouteLastTrackVectorPosition
Definition: TrackUnit.h:1681
TOneRoute::RouteID
int RouteID
the ID number of the route, this is needed for session saves
Definition: TrackUnit.h:1524
TAllRoutes
Handles data and functions relating to all routes on the railway.
Definition: TrackUnit.h:1610
TPrefDirElement::TrackVectorPosition
int TrackVectorPosition
TrackVectorPosition of the corresponding track element.
Definition: TrackUnit.h:222
TRailGraphics::sm121
Graphics::TBitmap * sm121
Definition: GraphicUnit.h:918
TUserGraphicItem::VPos
int VPos
Definition: DisplayUnit.h:34
Utilities.h
TTrainController::TContinuationAutoSigVectorIterator
TContinuationAutoSigVector::iterator TContinuationAutoSigVectorIterator
Definition: TrainUnit.h:678
TGraphicElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:454
TRailGraphics::sm46
Graphics::TBitmap * sm46
Definition: GraphicUnit.h:820
TTrack::SaveTrack
void SaveTrack(int Caller, std::ofstream &VecFile, bool GraphicsFollow)
Save all active and inactive track elements to VecFile.
Definition: TrackUnit.cpp:3242
TOneRoute::GetNonPreferredRouteStartElement
bool GetNonPreferredRouteStartElement(int Caller, int HLoc, int VLoc, bool Callon)
Set the starting conditions for a non-preferred (i.e. unrestricted) route selection beginning on HLoc...
Definition: TrackUnit.cpp:15495
TUserGraphicItem::HPos
int HPos
Definition: DisplayUnit.h:34
TDisplay::Update
void Update()
Repaint the screen display.
Definition: DisplayUnit.h:221
TRailGraphics::sm131striped
Graphics::TBitmap * sm131striped
Definition: GraphicUnit.h:777
TRailGraphics::gl63
Graphics::TBitmap * gl63
Definition: GraphicUnit.h:669
TRailGraphics::bm75grounddblwhite
Graphics::TBitmap * bm75grounddblwhite
Definition: GraphicUnit.h:500
TTrack::AdjElement
bool AdjElement(int Caller, int HLoc, int VLoc, int SpeedTag, int &FoundElement)
Used during location naming to check for adjacent named elements to a given element at HLoc & VLoc wi...
Definition: TrackUnit.cpp:8323
TOnePrefDir::EraseFromPrefDirVectorAnd4MultiMap
void EraseFromPrefDirVectorAnd4MultiMap(int Caller, int HLoc, int VLoc)
Erase element at HLoc and VLoc from the PrefDirVector and from the 4MultiMap. Note that this entails ...
Definition: TrackUnit.cpp:12685
Simple
@ Simple
Definition: TrackUnit.h:67
TTrack::GapFlashGreen
TGraphicElement * GapFlashGreen
Definition: TrackUnit.h:798
TRailGraphics::bm46
Graphics::TBitmap * bm46
Definition: GraphicUnit.h:444
TUtilities::RHSignalFlag
bool RHSignalFlag
new at v2.3.0 false=LH signals
Definition: Utilities.h:40
TRailGraphics::bm72dblyellow
Graphics::TBitmap * bm72dblyellow
Definition: GraphicUnit.h:478
TRailGraphics::sm22
Graphics::TBitmap * sm22
Definition: GraphicUnit.h:794
TTrack::NumberOfGaps
int NumberOfGaps(int Caller)
Returns the number of gaps in the railway.
Definition: TrackUnit.cpp:2853
TTrack::TSigElement::SigPtr
Graphics::TBitmap * SigPtr
pointer to the graphic
Definition: TrackUnit.h:730
TRailGraphics::BridgeNonSigRouteGraphicsPtr
Graphics::TBitmap * BridgeNonSigRouteGraphicsPtr[12]
route graphic for unrestricted route overlay
Definition: GraphicUnit.h:1006
TAllRoutes::FindRouteNumberFromRoute2MultiMapNoErrors
bool FindRouteNumberFromRoute2MultiMapNoErrors(int Caller, int HLoc, int VLoc, int ELink, int &RouteNumber)
If a route is present at H, V & Elink returns true with RouteNumber giving vector position in AllRout...
Definition: TrackUnit.cpp:18094
TRailGraphics::sm130
Graphics::TBitmap * sm130
Definition: GraphicUnit.h:775
TRailGraphics::sm45
Graphics::TBitmap * sm45
Definition: GraphicUnit.h:819
TRailGraphics::bm38
Graphics::TBitmap * bm38
Definition: GraphicUnit.h:425
TOnePrefDir::TPrefDirVectorIterator
std::vector< TPrefDirElement >::iterator TPrefDirVectorIterator
Definition: TrackUnit.h:1377
TRailGraphics::gl90unset
Graphics::TBitmap * gl90unset
Definition: GraphicUnit.h:706
TOnePrefDir::CheckPrefDirAgainstTrackVectorNoMessage
bool CheckPrefDirAgainstTrackVectorNoMessage(int Caller)
Check loaded PrefDir against loaded track, and if discrepancies found clear EveryPrefDir & PrefDir4Mu...
Definition: TrackUnit.cpp:12936
TTrack::WriteTrackAndTextToImage
void WriteTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveImageNoGrid1Click, TInterface::SaveImageAndGrid1Click and TInterface::SaveI...
Definition: TrackUnit.cpp:3835
TGraphicElement::TGraphicElement
TGraphicElement()
Default constructor (16 x 16 pixel element)
Definition: TrackUnit.cpp:1714
TRailGraphics::gl129Striped
Graphics::TBitmap * gl129Striped
Definition: GraphicUnit.h:595
TTrack::GetVectorPositionsFromInactiveTrackMap
TIMPair GetVectorPositionsFromInactiveTrackMap(int Caller, int HLoc, int VLoc, bool &FoundFlag)
Similar to GetVectorPositionFromTrackMap but for inactive elements, a pair is returned because there ...
Definition: TrackUnit.cpp:5749
TRailGraphics::gl64
Graphics::TBitmap * gl64
Definition: GraphicUnit.h:670
TTrain
Definition: TrainUnit.h:281
TPrefDirElement::TPrefDirElement
TPrefDirElement()
Default constructor, loads default values.
Definition: TrackUnit.h:394
TOnePrefDir::PresetAutoRouteDiagonalFouledByTrack
bool PresetAutoRouteDiagonalFouledByTrack(int Caller, TPrefDirElement ElementIn, int XLink)
Called by GetStartAndEndPrefDirElements...
Definition: TrackUnit.cpp:13780
TRailGraphics::bm77Striped
Graphics::TBitmap * bm77Striped
Definition: GraphicUnit.h:504
TFixedTrackPiece::TFixedTrackPiece
TFixedTrackPiece()
Default constructor.
Definition: TrackUnit.cpp:116
TTrackElement::TrainIDOnBridgeTrackPos23
int TrainIDOnBridgeTrackPos23
Set to the TrainID value when a train is present on the element, bridges can have two trains present ...
Definition: TrackUnit.h:154
TOnePrefDir::GetFixedPrefDirElementAt
const TPrefDirElement & GetFixedPrefDirElementAt(int Caller, int At) const
Return a non-modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11335
TRailGraphics::bm74grounddblred
Graphics::TBitmap * bm74grounddblred
Definition: GraphicUnit.h:493
TRailGraphics::gl1
Graphics::TBitmap * gl1
Definition: GraphicUnit.h:561
TTrack::LinkCheckArray
int LinkCheckArray[9][2]
array of valid link connecting values, I don't think this is used now
Definition: TrackUnit.h:588
TRailGraphics::sm66
Graphics::TBitmap * sm66
Definition: GraphicUnit.h:842
TTrack::TActiveLevelCrossing::VLoc
int VLoc
VLoc value for found level crossing element.
Definition: TrackUnit.h:644
TTrack::GetTruePositionsFromScreenPos
void GetTruePositionsFromScreenPos(int Caller, int &HPos, int &VPos, int ScreenPosH, int ScreenPosV)
Converse of GetScreenPositionsFromTruePos.
Definition: TrackUnit.cpp:7538
TRailGraphics::bm35
Graphics::TBitmap * bm35
Definition: GraphicUnit.h:416
TRailGraphics::bm10
Graphics::TBitmap * bm10
Definition: GraphicUnit.h:347
GapJump
@ GapJump
Definition: TrackUnit.h:67
TRailGraphics::bm45
Graphics::TBitmap * bm45
Definition: GraphicUnit.h:443
TRailGraphics::sm19
Graphics::TBitmap * sm19
Definition: GraphicUnit.h:790
TAllRoutes::AddRouteElement
void AddRouteElement(int Caller, int HLoc, int VLoc, int ELink, int RouteNumber, TPrefDirElement RouteElement)
A single TPrefDirElement is added to both PrefDirVector (for the route at RouteNumber) and Route2Mult...
Definition: TrackUnit.cpp:18455
TRailGraphics::sm82
Graphics::TBitmap * sm82
Definition: GraphicUnit.h:856
TTrack::AnyLinkedLevelCrossingElementsWithRoutesOrTrains
bool AnyLinkedLevelCrossingElementsWithRoutesOrTrains(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector, bool &TrainPresent)
True if a route or train present on any linked level crossing element.
Definition: TrackUnit.cpp:7284
TTrackElement::Length01
int Length01
Definition: TrackUnit.h:150
TRailGraphics::bm71dblyellow
Graphics::TBitmap * bm71dblyellow
Definition: GraphicUnit.h:472
TRailGraphics::sm124
Graphics::TBitmap * sm124
Definition: GraphicUnit.h:921
TRailGraphics::bm69CallingOn
Graphics::TBitmap * bm69CallingOn
Definition: GraphicUnit.h:458
TTrackElement::SpeedLimit01
int SpeedLimit01
Definition: TrackUnit.h:150
TTrack::Raising
@ Raising
Definition: TrackUnit.h:625
TRailGraphics::gl26
Graphics::TBitmap * gl26
Definition: GraphicUnit.h:628
TTrack::VLocMax
int VLocMax
give extent of railway for use in zoomed in and out displays and in saving railway images
Definition: TrackUnit.h:586
TTrack::UserGraphicMove
void UserGraphicMove(int Caller, int HPosInput, int VPosInput, int &UserGraphicItem, int &UserGraphicMoveHPos, int &UserGraphicMoveVPos, bool &UserGraphicFoundFlag)
handles moving of user graphics
Definition: TrackUnit.cpp:10321
TTextHandler::FindText
bool FindText(int Caller, AnsiString Name, int &HPos, int &VPos)
look in TextVector for text item 'Name', and if found return true and return its position in &HPos an...
Definition: TextUnit.cpp:585
TDisplay::DisplayOffsetV
static int DisplayOffsetV
the vertical offset of the displayed screen
Definition: DisplayUnit.h:78
TOneRoute::StartElement2
TPrefDirElement StartElement2
the two preferred direction elements corresponding to the starting position of a new route
Definition: TrackUnit.h:1528
TOneRoute::TRouteFlashElement::VLoc
int VLoc
Definition: TrackUnit.h:1492
TRailGraphics::gl86
Graphics::TBitmap * gl86
Definition: GraphicUnit.h:698
TRailGraphics::bm134
Graphics::TBitmap * bm134
Definition: GraphicUnit.h:366
TTrainController::BaseTime
TDateTime BaseTime
CurrentDateTime (i.e. real time) when operation restarts after a pause.
Definition: TrainUnit.h:651
TTrack::Tag129Array
int Tag129Array[8][3]
Definition: TrackUnit.h:598
TTrack::InactiveTrack2MultiMap
TInactiveTrack2MultiMap InactiveTrack2MultiMap
multimap of inactive TrackElements (see type for more information above)
Definition: TrackUnit.h:800
TRailGraphics::bm14
Graphics::TBitmap * bm14
Definition: GraphicUnit.h:386
TRailGraphics::sm106
Graphics::TBitmap * sm106
Definition: GraphicUnit.h:761
TRailGraphics::bm68dblyellow
Graphics::TBitmap * bm68dblyellow
Definition: GraphicUnit.h:453
TRailGraphics::gl97
Graphics::TBitmap * gl97
Definition: GraphicUnit.h:715
TOnePrefDir::PrefDirSize
unsigned int PrefDirSize() const
Return the vector size.
Definition: TrackUnit.h:1386
TTrack::PlotSignal
void PlotSignal(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plot signals on screen according to their aspect (Attribute value)
Definition: TrackUnit.cpp:5981
End
@ End
Definition: TrackUnit.h:77
TUserGraphicItem
Definition: DisplayUnit.h:31
TOneRoute::RouteFlash
TRouteFlash RouteFlash
the class member that allows the route to flash during setting up (see TRouteFlash above)
Definition: TrackUnit.h:1530
TRailGraphics::gl62
Graphics::TBitmap * gl62
Definition: GraphicUnit.h:668
TRailGraphics::sm67
Graphics::TBitmap * sm67
Definition: GraphicUnit.h:843
TTrack::TActiveLevelCrossing::BarrierState
TBarrierState BarrierState
state of barriers - Raising, Lowering, Up, Down (an enum - see above)
Definition: TrackUnit.h:636
TTrack::TimetabledLocationNameAllocated
bool TimetabledLocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found as a timetabled location name i.e. not as a continuation name.
Definition: TrackUnit.cpp:8677
TRailGraphics::sm9
Graphics::TBitmap * sm9
Definition: GraphicUnit.h:864
TRailGraphics::sm68
Graphics::TBitmap * sm68
Definition: GraphicUnit.h:904
clB0G0R5
#define clB0G0R5
Definition: GraphicUnit.h:41
TTrack::TrackFinished
bool TrackFinished
marker for all Conn & ConnLinkPos values set & track complete
Definition: TrackUnit.h:581
TTrack::InactiveTrackElementAt
TTrackElement & InactiveTrackElementAt(int Caller, int At)
A range-checked version of InactiveTrackVector.at(At)
Definition: TrackUnit.cpp:10430
TRailGraphics::LinkNonSigRouteGraphicsPtr
Graphics::TBitmap * LinkNonSigRouteGraphicsPtr[30]
unrestricted route graphic overlay
Definition: GraphicUnit.h:1019
TPrefDirElement::GetTrackVectorPosition
unsigned int GetTrackVectorPosition() const
Returns TrackVectorPosition.
Definition: TrackUnit.h:317
TRailGraphics::sm28
Graphics::TBitmap * sm28
Definition: GraphicUnit.h:800
TTrack::RouteFailMessage
AnsiString RouteFailMessage
Definition: TrackUnit.h:743
clB0G5R0
#define clB0G5R0
Definition: GraphicUnit.h:71
TTrack::LNPendingList
TLNPendingList LNPendingList
list of location name elements awaiting processing (see type for more information above)
Definition: TrackUnit.h:806
TRailGraphics::gl114
Graphics::TBitmap * gl114
Definition: GraphicUnit.h:578
TRailGraphics::sm116
Graphics::TBitmap * sm116
Definition: GraphicUnit.h:914
TTrackElement
Basic track elements as implemented in the overall railway layout.
Definition: TrackUnit.h:126
TRailGraphics::LCLHSVer
Graphics::TBitmap * LCLHSVer
Definition: GraphicUnit.h:723
TRailGraphics::bm74dblyellow
Graphics::TBitmap * bm74dblyellow
Definition: GraphicUnit.h:492
TRailGraphics::sm103
Graphics::TBitmap * sm103
Definition: GraphicUnit.h:758
TTrack::RebuildUserGraphics
void RebuildUserGraphics(int Caller, TDisplay *Disp)
rebuild user graphics
Definition: TrackUnit.cpp:3809
TRailGraphics::bmSolidBgnd
Graphics::TBitmap * bmSolidBgnd
Definition: GraphicUnit.h:990
TTrack::GroundSignalBuild
@ GroundSignalBuild
Definition: TrackUnit.h:862
TRailGraphics::smSolidBgnd
Graphics::TBitmap * smSolidBgnd
Definition: GraphicUnit.h:991
TPrefDirElement::PrefDirRoute
bool PrefDirRoute
marker within the route for preferred direction route element
Definition: TrackUnit.h:244
TTextHandler::WriteTextToImage
void WriteTextToImage(int Caller, Graphics::TBitmap *Bitmap)
write all items in TextVector to the railway image in 'Bitmap'
Definition: TextUnit.cpp:442
TRailGraphics::bmNameStriped
Graphics::TBitmap * bmNameStriped
Definition: GraphicUnit.h:525
TRailGraphics::gl88unset
Graphics::TBitmap * gl88unset
Definition: GraphicUnit.h:701
SignalPost
@ SignalPost
Definition: TrackUnit.h:67
TTrack::SetAllDefaultLengthsAndSpeedLimits
void SetAllDefaultLengthsAndSpeedLimits(int Caller)
Work through all elements in TrackVector setting all lengths & speed limits to default values - inclu...
Definition: TrackUnit.cpp:9392
TRailGraphics::BridgeGraphicsPtr
Graphics::TBitmap * BridgeGraphicsPtr[12]
basic graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1000
TRailGraphics::bm69green
Graphics::TBitmap * bm69green
Definition: GraphicUnit.h:462
TAllRoutes::WriteAllRoutesToImage
void WriteAllRoutesToImage(int Caller, Graphics::TBitmap *Bitmap)
Calls RouteImageMarker for each route in turn to display the route colours and direction arrows on th...
Definition: TrackUnit.cpp:17498
IDInt::GetInt
int GetInt() const
get the internal integer
Definition: TrackUnit.h:520
TRailGraphics::sm132
Graphics::TBitmap * sm132
Definition: GraphicUnit.h:778
TPrefDirElement::operator!=
bool operator!=(TPrefDirElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:1071
TAllRoutes::TRoute2MultiMapIterator
TRoute2MultiMap::iterator TRoute2MultiMapIterator
Definition: TrackUnit.h:1647
TRailGraphics::sm20
Graphics::TBitmap * sm20
Definition: GraphicUnit.h:792
TRailGraphics::sm52
Graphics::TBitmap * sm52
Definition: GraphicUnit.h:827
TTrack::GetScreenPositionsFromTruePos
void GetScreenPositionsFromTruePos(int Caller, int &ScreenPosH, int &ScreenPosV, int HPosTrue, int VPosTrue)
With large railways only part of the railway is displayed on screen, and this function converts true ...
Definition: TrackUnit.cpp:7552
TRailGraphics::bm68yellow
Graphics::TBitmap * bm68yellow
Definition: GraphicUnit.h:457
TTrack::TInactiveTrackRange
std::pair< TInactiveTrack2MultiMapIterator, TInactiveTrack2MultiMapIterator > TInactiveTrackRange
range for TInactiveTrack2MultiMap
Definition: TrackUnit.h:685
TRailGraphics::bm31
Graphics::TBitmap * bm31
Definition: GraphicUnit.h:404
TTrack::PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainLoweredLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp, bool Manual)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway (...
Definition: TrackUnit.cpp:6730
TTrack::TTrackVector
std::vector< TTrackElement > TTrackVector
vector of TrackElements
Definition: TrackUnit.h:661
TPrefDirElement::AutoSignals
bool AutoSignals
marker within the route for an AutoSignal route element
Definition: TrackUnit.h:242
TRailGraphics::bm74CallingOn
Graphics::TBitmap * bm74CallingOn
Definition: GraphicUnit.h:491
TRailGraphics::gl76
Graphics::TBitmap * gl76
Definition: GraphicUnit.h:685
FirstUnusedSpeedTagNumber
#define FirstUnusedSpeedTagNumber
Definition: TrackUnit.h:36
TTrack::EraseLocationAndActiveTrackElementNames
void EraseLocationAndActiveTrackElementNames(int Caller, AnsiString LocationName)
Examines LocationNameMultiMap and if the LocationName is found all elements at that H & V (in both ac...
Definition: TrackUnit.cpp:8716
TRailGraphics::sm71
Graphics::TBitmap * sm71
Definition: GraphicUnit.h:907
TRailGraphics::sm43
Graphics::TBitmap * sm43
Definition: GraphicUnit.h:817
TAllRoutes::MarkAllRoutes
void MarkAllRoutes(int Caller, TDisplay *Disp)
Calls PrefDirMarker for all routes, with RouteCall set to identify a route call, and BuildingPrefDir ...
Definition: TrackUnit.cpp:17483
TRailGraphics::sm101
Graphics::TBitmap * sm101
Definition: GraphicUnit.h:756
Concourse
@ Concourse
Definition: TrackUnit.h:68
TTrack::BotPlatAllowed
Set< int, 1, 146 > BotPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::gl52
Graphics::TBitmap * gl52
Definition: GraphicUnit.h:657
TTrack::SelectVector
TTrackVector SelectVector
vectors of TrackElements
Definition: TrackUnit.h:815
TRailGraphics::sm29
Graphics::TBitmap * sm29
Definition: GraphicUnit.h:801
TConfiguration
TConfiguration
< describes the type of track link. 'End' is used for both buffer stop and continuation entry/exit po...
Definition: TrackUnit.h:76
TOnePrefDir::WritePrefDirToImage
void WritePrefDirToImage(int Caller, Graphics::TBitmap *Bitmap)
Used when creating a bitmap image to display preferred directions (as on screen during 'Set preferred...
Definition: TrackUnit.cpp:13550
TOnePrefDir::DecrementPrefDirElementNumbersInPrefDir4MultiMap
void DecrementPrefDirElementNumbersInPrefDir4MultiMap(int Caller, unsigned int ErasedElementNumber)
Called after ErasePrefDirElementAt to decrement the remaining PrefDirElementNumbers in 4MultiMap if t...
Definition: TrackUnit.cpp:13287
TTrackElement::LogTrack
AnsiString LogTrack(int Caller) const
Used to log track parameters for call stack logging.
Definition: TrackUnit.cpp:230
TRailGraphics::gl95unset
Graphics::TBitmap * gl95unset
Definition: GraphicUnit.h:714
TTrack::TrackVectorSize
int TrackVectorSize()
Return the number of active track elements.
Definition: TrackUnit.h:915
TTrackType
TTrackType
< describes the type of track element
Definition: TrackUnit.h:66
TRailGraphics::bm77
Graphics::TBitmap * bm77
Definition: GraphicUnit.h:503
TTrack::NoGaps
bool NoGaps(int Caller)
True if there are no gaps.
Definition: TrackUnit.cpp:4516
TGraphicElement::PlotOriginal
void PlotOriginal(int Caller, TDisplay *Disp)
Plot the original graphic on screen.
Definition: TrackUnit.cpp:1858
TextHandler
TTextHandler * TextHandler
Definition: TextUnit.cpp:95
TRailGraphics::bm39
Graphics::TBitmap * bm39
Definition: GraphicUnit.h:428
TRailGraphics::sm40
Graphics::TBitmap * sm40
Definition: GraphicUnit.h:814
TRailGraphics::bm41
Graphics::TBitmap * bm41
Definition: GraphicUnit.h:434
TRailGraphics::sm54
Graphics::TBitmap * sm54
Definition: GraphicUnit.h:829
TRailGraphics::bm72green
Graphics::TBitmap * bm72green
Definition: GraphicUnit.h:481
TRailGraphics::gl129
Graphics::TBitmap * gl129
Definition: GraphicUnit.h:594
TRailGraphics::sm31
Graphics::TBitmap * sm31
Definition: GraphicUnit.h:804
TGraphicElement::ExistingGraphicLoaded
bool ExistingGraphicLoaded
state flags
Definition: TrackUnit.h:448
TRailGraphics::bm74green
Graphics::TBitmap * bm74green
Definition: GraphicUnit.h:495
TUserGraphicItem::Width
int Width
Definition: DisplayUnit.h:35
TTrack::MirrorArray
int MirrorArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'mirroring' via menu items 'Edit' & 'Mirror'
Definition: TrackUnit.h:780
TRailGraphics::bm71grounddblred
Graphics::TBitmap * bm71grounddblred
Definition: GraphicUnit.h:473
Utilities
TUtilities * Utilities
Definition: Utilities.cpp:47
TFixedTrackPiece::SmallGraphicPtr
Graphics::TBitmap * SmallGraphicPtr
the track bitmap for display on the zoomed-out railway
Definition: TrackUnit.h:95
TRailGraphics::bm40
Graphics::TBitmap * bm40
Definition: GraphicUnit.h:431
TRailGraphics::sm42
Graphics::TBitmap * sm42
Definition: GraphicUnit.h:816
TRailGraphics::gl111
Graphics::TBitmap * gl111
Definition: GraphicUnit.h:575
TTrack::IsATrackElementAdjacentToLink
bool IsATrackElementAdjacentToLink(int Caller, int HLocIn, int VLocIn, int LinkIn)
True if there is an element adjacent to LinkIn for element at HLoc & VLoc.
Definition: TrackUnit.cpp:10908
TAllRoutes::DecrementRouteNumbersInRoute2MultiMap
void DecrementRouteNumbersInRoute2MultiMap(int Caller, int RouteNumber)
After a route has been erased from AllRoutesVector and its entries from Route2MultiMap,...
Definition: TrackUnit.cpp:18299
TTrack::BuildGapMapFromTrackVector
void BuildGapMapFromTrackVector(int Caller)
Examine TrackVector and whenever find a new gap pair enter it into GapMap.
Definition: TrackUnit.cpp:4750
TTrackElement::ThreeAspect
@ ThreeAspect
Definition: TrackUnit.h:159
TTrack::NoActiveOrInactiveTrack
bool NoActiveOrInactiveTrack(int Caller)
True if there is no active or inactive track in the railway.
Definition: TrackUnit.cpp:1877
TRailGraphics::gl68
Graphics::TBitmap * gl68
Definition: GraphicUnit.h:674
TRailGraphics::sm18
Graphics::TBitmap * sm18
Definition: GraphicUnit.h:789
TRailGraphics::sm128
Graphics::TBitmap * sm128
Definition: GraphicUnit.h:925
TTrack::SuppressRouteFailMessage
bool SuppressRouteFailMessage
true if a message has been given in the search routine, to avoid giving multiple times and to avoid o...
Definition: TrackUnit.h:759
TTrack::FixedTrackArray
TFixedTrackArray FixedTrackArray
the FixedTrackPiece array object
Definition: TrackUnit.h:576
TDisplay::DisplayZoomOutOffsetVHome
static int DisplayZoomOutOffsetVHome
the vertical offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:90
TRailGraphics::gl121
Graphics::TBitmap * gl121
Definition: GraphicUnit.h:586
TRailGraphics::LCBothHor
Graphics::TBitmap * LCBothHor
Definition: GraphicUnit.h:720
TRailGraphics::sm6
Graphics::TBitmap * sm6
Definition: GraphicUnit.h:835
TPrefDirElement::GetOriginalGraphicPtr
Graphics::TBitmap * GetOriginalGraphicPtr()
picks up the original (non-flashing) graphic for use during route flashing
Definition: TrackUnit.cpp:444
TTrack::TTrackMap
std::map< THVPair, unsigned int, TMapComp > TTrackMap
map of TrackElement TrackVectorPositions, HLoc & VLoc pair is the key
Definition: TrackUnit.h:670
TTrack::DiagonalFouledByTrain
bool DiagonalFouledByTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber, int &TrainID)
As DiagonalFouledByRouteOrTrain (in TAllRoutes) but only checks for a train (may or may not be a rout...
Definition: TrackUnit.cpp:11153
TAllRoutes::IsThereARouteAtIDNumber
bool IsThereARouteAtIDNumber(int Caller, IDInt RouteID)
Returns true if there is a route with the given ID number - added at v1.3.1 (see function for details...
Definition: TrackUnit.cpp:18921
TTrack::NameAllowed
Set< int, 1, 146 > NameAllowed
Definition: TrackUnit.h:604
TRailGraphics::LinkSigRouteGraphicsPtr
Graphics::TBitmap * LinkSigRouteGraphicsPtr[30]
preferred direction route graphic overlay
Definition: GraphicUnit.h:1017
TRailGraphics::gl142
Graphics::TBitmap * gl142
Definition: GraphicUnit.h:611
TTrack::ReturnNextTrackElement
bool ReturnNextTrackElement(int Caller, TTrackElement &Next)
Return a reference to the active track element pointed to by NextTrackElementPtr (during zoomed-in or...
Definition: TrackUnit.cpp:2821
TRailGraphics::gl92unset
Graphics::TBitmap * gl92unset
Definition: GraphicUnit.h:710
TOneRoute::ClearRoute
void ClearRoute()
Empty the route of any stored elements.
Definition: TrackUnit.h:1536
TTrack::ResetAllTrainIDElements
void ResetAllTrainIDElements(int Caller)
Track elements have members that indicates whether and on what track a train is present (TrainIDOnEle...
Definition: TrackUnit.cpp:7509
TOneRoute::RouteImageMarker
void RouteImageMarker(int Caller, Graphics::TBitmap *Bitmap) const
Used when creating a bitmap image to display the route colours and direction arrows (as on screen dur...
Definition: TrackUnit.cpp:14726
TTrack::IsLCBarrierUpAtHV
bool IsLCBarrierUpAtHV(int Caller, int HLoc, int VLoc)
True if a closed (to trains) level crossing is found at H & V.
Definition: TrackUnit.cpp:7165
TTrack::LocationNameAllocated
bool LocationNameAllocated(int Caller, AnsiString LocationName)
True if a non-empty LocationName found in LocationNameMultiMap.
Definition: TrackUnit.cpp:8513
TTrack::SetLCAttributeAtHV
void SetLCAttributeAtHV(int Caller, int HLoc, int VLoc, int Attr)
Set LC attribute at H & V; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to tra...
Definition: TrackUnit.cpp:7244
TRailGraphics::gl61
Graphics::TBitmap * gl61
Definition: GraphicUnit.h:667
TRailGraphics::LCBotHor
Graphics::TBitmap * LCBotHor
Definition: GraphicUnit.h:721
TTrack::GetTrackElementFromAnyTrackMap
TTrackElement & GetTrackElementFromAnyTrackMap(int Caller, int HLoc, int VLoc, TTrackMap &Map, TTrackVector &Vector)
Return a reference to the element at HLoc & VLoc for any map and any vector (used for SelectPrefDir i...
Definition: TrackUnit.cpp:5660
TTrack::TLocationNameMultiMapEntry
std::pair< AnsiString, int > TLocationNameMultiMapEntry
Definition: TrackUnit.h:707
TRailGraphics::gl55
Graphics::TBitmap * gl55
Definition: GraphicUnit.h:660
TUtilities::CallLogPop
void CallLogPop(int Caller)
pops the last entry off the call stack, throws an error if called when empty
Definition: Utilities.cpp:50
TTrain::MaximumSpeedLimit
static const int MaximumSpeedLimit
km/h
Definition: TrainUnit.h:294
TTrack::TLNDone2MultiMapIterator
TLNDone2MultiMap::iterator TLNDone2MultiMapIterator
during naming of linked named location elements, '2' because there
Definition: TrackUnit.h:698
TOnePrefDir::PrefDir4MultiMap
TPrefDir4MultiMap PrefDir4MultiMap
the pref dir multimap - up to 4 values (up to 2 tracks per element each with 2 directions)
Definition: TrackUnit.h:1312
TTrack::ThreeAspectBuild
@ ThreeAspectBuild
Definition: TrackUnit.h:862
TRailGraphics::sm30
Graphics::TBitmap * sm30
Definition: GraphicUnit.h:803
TRailGraphics::bm85
Graphics::TBitmap * bm85
Definition: GraphicUnit.h:510
TRailGraphics::sm3
Graphics::TBitmap * sm3
Definition: GraphicUnit.h:802
TRailGraphics::bm70yellow
Graphics::TBitmap * bm70yellow
Definition: GraphicUnit.h:470
TOnePrefDir::GetVectorPositionsFromPrefDir4MultiMap
void GetVectorPositionsFromPrefDir4MultiMap(int Caller, int HLoc, int VLoc, bool &FoundFlag, int &PrefDirPos0, int &PrefDirPos1, int &PrefDirPos2, int &PrefDirPos3)
Return up to 4 vector positions for a given HLoc & VLoc; unused values return -1.
Definition: TrackUnit.cpp:13024
TRailGraphics::sm110
Graphics::TBitmap * sm110
Definition: GraphicUnit.h:766
TRailGraphics::sm92
Graphics::TBitmap * sm92
Definition: GraphicUnit.h:867
TOnePrefDir::GetPrefDirTruncateElement
bool GetPrefDirTruncateElement(int Caller, int HLoc, int VLoc)
Called during PrefDir build or distance setting. It truncates at & including the first element in the...
Definition: TrackUnit.cpp:12159
TAllRoutes::TRoute2MultiMapEntry
std::pair< THVPair, TRouteElementPair > TRoute2MultiMapEntry
Definition: TrackUnit.h:1648
TDisplay::PlotOutput
void PlotOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot the graphic at screen position HPos & VPos.
Definition: DisplayUnit.cpp:85
TAllRoutes::AllRoutesVector
TAllRoutesVector AllRoutesVector
the vector that stores all the routes on the railway
Definition: TrackUnit.h:1700
TUtilities::SaveFileBool
void SaveFileBool(std::ofstream &OutFile, bool SaveBool)
stores '1' if the bool is true or '0' if false to the file, then a CR
Definition: Utilities.cpp:108
TPrefDirVector
std::vector< TPrefDirElement > TPrefDirVector
forward declaration because needed in TTrack
Definition: TrackUnit.h:47
TRailGraphics::sm69
Graphics::TBitmap * sm69
Definition: GraphicUnit.h:905
TRailGraphics::gl123
Graphics::TBitmap * gl123
Definition: GraphicUnit.h:588
TOnePrefDir::SaveSearchVector
void SaveSearchVector(int Caller, std::ofstream &VecFile)
Save the search vector to a file.
Definition: TrackUnit.cpp:12652
TRailGraphics::gl48
Graphics::TBitmap * gl48
Definition: GraphicUnit.h:652
TOneRoute::ForceCancelRoute
void ForceCancelRoute(int Caller)
Cancel a route immediately if a train occupies it when travelling in the wrong direction (or occupies...
Definition: TrackUnit.cpp:17270
TTrack::SaveChangingLCVector
void SaveChangingLCVector(int Caller, std::ofstream &OutFile)
Save all changing vector values (used for error file)
Definition: TrackUnit.cpp:3619
TTrackElement::PlotVariableTrackElement
void PlotVariableTrackElement(int Caller, TDisplay *Disp) const
Plot the element on the display 'variable' indicates that the element may be named and if so may be p...
Definition: TrackUnit.cpp:169
TOnePrefDir::StorePrefDirElement
void StorePrefDirElement(int Caller, TPrefDirElement LoadPrefDirElement)
Store a single pref dir element in the vector & map.
Definition: TrackUnit.cpp:13240
TTrack::SaveUserGraphics
void SaveUserGraphics(int Caller, std::ofstream &VecFile)
save graphics
Definition: TrackUnit.cpp:11196
TTrack::ThisNamedLocationLongEnoughForSplit
bool ThisNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName, int FirstNamedElementPos, int &SecondNamedElementPos, int &FirstNamedLinkedElementPos, int &SecondNamedLinkedElementPos)
See above under 'OneNamedLocationLongEnoughForSplit'.
Definition: TrackUnit.cpp:10571
TGraphicElement::LoadOriginalScreenGraphic
void LoadOriginalScreenGraphic(int Caller)
Load original graphic from the screen for point flashing or route start markers.
Definition: TrackUnit.cpp:1760
TRailGraphics::sm109
Graphics::TBitmap * sm109
Definition: GraphicUnit.h:764
TTrack::SelectVectorSize
unsigned int SelectVectorSize()
Return the number of selected active and inactive track elements (via menu items 'Edit' and 'Select')
Definition: TrackUnit.h:927
TRailGraphics::bm74yellow
Graphics::TBitmap * bm74yellow
Definition: GraphicUnit.h:496
TTrack::Tag78Array
int Tag78Array[25][3]
Definition: TrackUnit.h:595
TTrack::PlotGap
void PlotGap(int Caller, TTrackElement TrackElement, TDisplay *Disp)
Plots a gap on screen - may be set or unset.
Definition: TrackUnit.cpp:5843
TPrefDirElement::GetDirectionPrefDirGraphicPtr
Graphics::TBitmap * GetDirectionPrefDirGraphicPtr() const
picks up the EntryDirectionGraphicPtr for preferred directions
Definition: TrackUnit.cpp:1009
TOnePrefDir::LoadPrefDir
void LoadPrefDir(int Caller, std::ifstream &VecFile)
Load a vector and map of preferred directions from the file.
Definition: TrackUnit.cpp:12472
Under
@ Under
Definition: TrackUnit.h:77
TRailGraphics::bm59
Graphics::TBitmap * bm59
Definition: GraphicUnit.h:450
TOneRoute::PointsToBeChanged
bool PointsToBeChanged(int Caller) const
Called by GetNextNonPreferredRouteElement and GetNextPreferredRouteElement to check whether or not an...
Definition: TrackUnit.cpp:16780
TTrack::TrackVector
TTrackVector TrackVector
Definition: TrackUnit.h:815
TRailGraphics::gl84
Graphics::TBitmap * gl84
Definition: GraphicUnit.h:696
TTrack::TActiveLevelCrossing::BaseElementSpeedTag
int BaseElementSpeedTag
SpeedTag value for the base element of a level crossing.
Definition: TrackUnit.h:640
TTrackElement::operator!=
bool operator!=(TTrackElement RHElement)
non-equivalence operator
Definition: TrackUnit.cpp:155
TTrack::ResetConnClkCheckUnsetGapJumps
bool ResetConnClkCheckUnsetGapJumps(int Caller)
Sets all Conns and CLks to -1 except for gapjumps that match and are properly set,...
Definition: TrackUnit.cpp:2876
TOnePrefDir::GetModifiablePrefDirElementAt
TPrefDirElement & GetModifiablePrefDirElementAt(int Caller, int At)
Return a modifiable element at PrefDirVector position 'At'.
Definition: TrackUnit.cpp:11347
TOnePrefDir::SearchForPrefDir
bool SearchForPrefDir(int Caller, TTrackElement TrackElement, int XLinkPos, int RequiredPosition)
Try to find a selected element from a given start position. Enter with CurrentTrackElement stored in ...
Definition: TrackUnit.cpp:11667
TRailGraphics::sm96
Graphics::TBitmap * sm96
Definition: GraphicUnit.h:871
TGraphicElement
Allows a single Width x Height graphic to change and change back independently of the remaining displ...
Definition: TrackUnit.h:445
TTrackElement::CallingOnSet
bool CallingOnSet
Used for for signals only when a train is being called on - used to plot the position lights.
Definition: TrackUnit.h:136
TUtilities::SaveFileInt
void SaveFileInt(std::ofstream &OutFile, int SaveInt)
stores the int value to the file, then a CR
Definition: Utilities.cpp:121
TrainController
TTrainController * TrainController
the object pointer, one object only - created in InterfaceUnit
Definition: TrainUnit.cpp:54
TTrack::OneNamedLocationLongEnoughForSplit
bool OneNamedLocationLongEnoughForSplit(int Caller, AnsiString LocationName)
Definition: TrackUnit.cpp:10465
Lead
@ Lead
Definition: TrackUnit.h:77
TTrack::TrackElementPresentAtHV
bool TrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if a track element present (not inactive elements - see InactiveTrackElementPrese...
Definition: TrackUnit.cpp:5708
TGraphicElement::LoadOriginalExistingGraphic
void LoadOriginalExistingGraphic(int Caller, int HOffset, int VOffset, int WidthIn, int HeightIn, Graphics::TBitmap *Graphic)
Load red or green gap flashing graphic from the stored bitmaps.
Definition: TrackUnit.cpp:1794
TOnePrefDir::CalcDistanceAndSpeed
void CalcDistanceAndSpeed(int Caller, int &OverallDistance, int &OverallSpeedLimit, bool &LeadingPointsAtLastElement)
Used when setting element lengths, returns in &OverallDistance the overall distance for the selected ...
Definition: TrackUnit.cpp:13488
TTrack::GetHLocMin
int GetHLocMin()
Definition: TrackUnit.h:881
TTextHandler::TextPtrAt
TTextItem * TextPtrAt(int Caller, int At)
return the text item at position 'At' in TextVector (carries out range checking)
Definition: TextUnit.cpp:555
TUtilities::CheckFileInt
bool CheckFileInt(std::ifstream &InFile, int Lowest, int Highest)
checks that the value is an int lying between Lowest & Highest (inclusive), returns true for success
Definition: Utilities.cpp:238
TTrack::TrackPush
void TrackPush(int Caller, TTrackElement TrackElement)
Insert TrackElement into the relevant vector and map, and, if named, insert the name in LocationNameM...
Definition: TrackUnit.cpp:5500
TTrack::IsBarrierDownVectorAtHVManual
bool IsBarrierDownVectorAtHVManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
True if there is a vector entry at H & V that is set to manual (TypeOfRoute == 2) and returns the vec...
Definition: TrackUnit.cpp:6302
TFixedTrackPiece::FixedNamedLocationElement
bool FixedNamedLocationElement
true for an element that can be named (platforms, concourse, footcrossings & non-station named loacti...
Definition: TrackUnit.h:87
TOnePrefDir::PrefDirSearchLimit
static const int PrefDirSearchLimit
limit to the number of elements searched in attempting to find a preferred direction
Definition: TrackUnit.h:1341
TTrack::GetTrackVectorIteratorFromNamePosition
TTrackVectorIterator GetTrackVectorIteratorFromNamePosition(int Caller, int Position)
Takes an adjusted vector position value from either vector (if active, Position = -TruePos -1,...
Definition: TrackUnit.cpp:9188
TRailGraphics::bm70grounddblwhite
Graphics::TBitmap * bm70grounddblwhite
Definition: GraphicUnit.h:468
TRailGraphics::bm70green
Graphics::TBitmap * bm70green
Definition: GraphicUnit.h:469
TRailGraphics::gl115
Graphics::TBitmap * gl115
Definition: GraphicUnit.h:579
TTrack::Up
@ Up
Definition: TrackUnit.h:625
TRailGraphics::sm89
Graphics::TBitmap * sm89
Definition: GraphicUnit.h:863
TTrack::NextTrackElementPtr
TTrackVectorIterator NextTrackElementPtr
track vector iterator used during cycling through a track vector
Definition: TrackUnit.h:817
TTrack::Tag130Array
int Tag130Array[8][3]
Definition: TrackUnit.h:599
TTrack::BlankElementAt
bool BlankElementAt(int Caller, int At) const
True for a blank (SpeedTag == 0) element at a specific Trackvector position, no longer used after Tra...
Definition: TrackUnit.cpp:10444
TRailGraphics::sm127
Graphics::TBitmap * sm127
Definition: GraphicUnit.h:924
TOneRoute
A descendent of TOnePrefDir used for routes. Used during contruction of a route (ConstructRoute) and ...
Definition: TrackUnit.h:1486
TDisplay::PlotSignalBlankOnBitmap
void PlotSignalBlankOnBitmap(int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *Bitmap, bool RHSFlag)
Definition: DisplayUnit.cpp:378
TTrack::NamedLocationElementAt
bool NamedLocationElementAt(int Caller, int HLoc, int VLoc)
True if the active or inactive TrackElement at HLoc & VLoc has its FixedNamedLocationElement member t...
Definition: TrackUnit.cpp:8480
TAllRoutes::TLockedRouteVectorIterator
std::vector< TLockedRouteClass >::iterator TLockedRouteVectorIterator
Definition: TrackUnit.h:1641
TTrack::LCFoundInAutoSigsRoute
bool LCFoundInAutoSigsRoute
true if found an LC during an automatic route search
Definition: TrackUnit.h:755
TPrefDirElement::XLink
int XLink
Definition: TrackUnit.h:218
TOneRoute::SetRouteFlashValues
void SetRouteFlashValues(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
After a route has been selected successfully this function sets all RouteFlash (see above) values app...
Definition: TrackUnit.cpp:17337
TAllRoutes::TRouteType
TRouteType
Definition: TrackUnit.h:1630
TRailGraphics::bm133
Graphics::TBitmap * bm133
Definition: GraphicUnit.h:363
TRailGraphics::sm135
Graphics::TBitmap * sm135
Definition: GraphicUnit.h:781
Crossover
@ Crossover
Definition: TrackUnit.h:67
TTrack::SetLinkedManualLCs
void SetLinkedManualLCs(int Caller, int HLoc, int VLoc)
Set all TypeOfRoute values to 2 for all linked LCs to indicate manually lowered.
Definition: TrackUnit.cpp:6188
TRailGraphics::bm71green
Graphics::TBitmap * bm71green
Definition: GraphicUnit.h:475
TRailGraphics::bm51
Graphics::TBitmap * bm51
Definition: GraphicUnit.h:446
TTrack::UGME
TUserGraphicMapEntry UGME
an entry for the UserGraphicMap
Definition: TrackUnit.h:819
TRailGraphics::gl21
Graphics::TBitmap * gl21
Definition: GraphicUnit.h:623
TTrack::ElementInLNDone2MultiMap
bool ElementInLNDone2MultiMap(int Caller, int MapPos)
True if the element defined by MapPos is present in LNDone2MultiMap, used during location naming.
Definition: TrackUnit.cpp:8426
TRailGraphics::sm137
Graphics::TBitmap * sm137
Definition: GraphicUnit.h:783
TTrack::IsLCBarrierFlashingAtHV
bool IsLCBarrierFlashingAtHV(int Caller, int HLoc, int VLoc)
True if barrier is in process of opening or closing at H & V.
Definition: TrackUnit.cpp:7193
TTrack::IsPlatformOrNamedNonStationLocationPresent
bool IsPlatformOrNamedNonStationLocationPresent(int Caller, int HLoc, int VLoc)
True if a non-station named location or platform at HLoc & VLoc.
Definition: TrackUnit.cpp:9855
DefaultTrackLength
#define DefaultTrackLength
Definition: TrackUnit.h:37
TRailGraphics::bm68CallingOn
Graphics::TBitmap * bm68CallingOn
Definition: GraphicUnit.h:452
Signal
@ Signal
Definition: TrackUnit.h:77
TTrack::VLocMin
int VLocMin
Definition: TrackUnit.h:586
TTrack::LevelCrossingAllowed
Set< int, 1, 146 > LevelCrossingAllowed
sets of valid TrackElements for placement of platforms and non-station named locations
Definition: TrackUnit.h:604
TRailGraphics::bm69grounddblwhite
Graphics::TBitmap * bm69grounddblwhite
Definition: GraphicUnit.h:461
TTrack::ContinuationNameMap
std::map< AnsiString, char > ContinuationNameMap
map of all continuation names, char is a dummy
Definition: TrackUnit.h:787
TAllRoutes::GetRouteTypeAndNumber
TRouteType GetRouteTypeAndNumber(int Caller, int TrackVectorPosition, int LinkPos, int &RouteNumber)
Examines Route2MultiMap and if the element at TrackVectorPosition with LinkPos (can be entry or exit)...
Definition: TrackUnit.cpp:17787
TTrackElement::TrainIDOnBridgeTrackPos01
int TrainIDOnBridgeTrackPos01
Definition: TrackUnit.h:154
TTrack::TFixedTrackArray::TFixedTrackArray
TFixedTrackArray()
Array constructor.
Definition: TrackUnit.cpp:1528
TOnePrefDir::CheckOnePrefDir
bool CheckOnePrefDir(int Caller, int NumberOfActiveElements, std::ifstream &VecFile)
Called before PrefDir loading as part of the FileIntegrityCheck function in case there is an error in...
Definition: TrackUnit.cpp:12522
TRailGraphics::bm78Striped
Graphics::TBitmap * bm78Striped
Definition: GraphicUnit.h:506
TTrack::TrainOnLink
bool TrainOnLink(int Caller, int HLoc, int VLoc, int Link, int &TrainID)
New at v1.2.0; checks whether a train present at input location and link and returns its ID if so.
Definition: TrackUnit.cpp:11092
TTrack::ResetAnyNonMatchingGaps
void ResetAnyNonMatchingGaps(int Caller)
Called by EraseTrackElement after the element has been erased and the vector positions changed,...
Definition: TrackUnit.cpp:4600
TTrack::GapPos
int GapPos
Definition: TrackUnit.h:584
TTrack::TrackElementAt
TTrackElement & TrackElementAt(int Caller, int At)
A range-checked version of TrackVector.at(At)
Definition: TrackUnit.cpp:10416
TGraphicElement::Width
int Width
Definition: TrackUnit.h:452
TAllRoutes::RouteLockingRequired
bool RouteLockingRequired(int Caller, int RouteNumber, int RouteTruncatePosition)
Route locking is required (returns true) if a moving train is within 3 signals back from the RouteTru...
Definition: TrackUnit.cpp:18695
TRailGraphics::bmGreenEllipse
Graphics::TBitmap * bmGreenEllipse
Definition: GraphicUnit.h:520
TAllRoutes::GetRouteVectorNumber
int GetRouteVectorNumber(int Caller, IDInt RouteID)
Returns a route's position in AllRoutesVector from its ID, throws an error if a matching route isn't ...
Definition: TrackUnit.cpp:18905
TAllRoutes::GetRouteTypeAndGraphics
TRouteType GetRouteTypeAndGraphics(int Caller, int TrackVectorPosition, int LinkPos, Graphics::TBitmap *&EXGraphicPtr, Graphics::TBitmap *&EntryDirectionGraphicPtr)
Examines Route2MultiMap for the element at TrackVectorPosition with LinkPos (can be entry or exit).
Definition: TrackUnit.cpp:17613
TTrack::ChangingLCVector
TActiveLCVector ChangingLCVector
vector of values for changing level crossings - i.e. barriers in course of being raised or lowered
Definition: TrackUnit.h:792
TRailGraphics::bm73green
Graphics::TBitmap * bm73green
Definition: GraphicUnit.h:488
TTrainController::StopTTClockFlag
bool StopTTClockFlag
when true the timetable clock is stopped, used for messages display and train popup menu display etc
Definition: TrainUnit.h:744
TRailGraphics::gl107
Graphics::TBitmap * gl107
Definition: GraphicUnit.h:570
TPrefDirElement::GetRouteGraphicPtr
Graphics::TBitmap * GetRouteGraphicPtr(bool AutoSigsFlag, bool PrefDirRoute)
picks up the appropriate route graphic
Definition: TrackUnit.cpp:636
TRailGraphics::bm53
Graphics::TBitmap * bm53
Definition: GraphicUnit.h:447
TUtilities::CheckAndReadFileString
bool CheckAndReadFileString(std::ifstream &InFile, AnsiString &OutString)
checks that the value is a string ('0' or CR accepted as delimiters), returns true for success and re...
Definition: Utilities.cpp:529
TRailGraphics::sm12
Graphics::TBitmap * sm12
Definition: GraphicUnit.h:771
TUserGraphicItem::FileName
AnsiString FileName
Definition: DisplayUnit.h:33
TOneRoute::GetNextPreferredRouteElement
bool GetNextPreferredRouteElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool ConsecSignals, bool AutoSigsFlag, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks that lie on preferred directions between the route start element a...
Definition: TrackUnit.cpp:14318
TTrack::TTrackMapIterator
TTrackMap::iterator TTrackMapIterator
Definition: TrackUnit.h:672
TTrack::WriteGraphicsToImage
void WriteGraphicsToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by SaveImageNoGridMenuItemClick, SaveImageAndGridMenuItemClick amd SaveImageAndPrefDirsMenuIte...
Definition: TrackUnit.cpp:4117
TTrack::PlotPastedTrackElementWithAttributes
void PlotPastedTrackElementWithAttributes(int Caller, TTrackElement TempTrackElement, int HLocInput, int VLocInput, bool &TrackLinkingRequiredFlag, bool InternalChecks)
new at v2.2.0 - as PlotAndAddTrackElement but keeping speed & length attributes (for pasting) and als...
Definition: TrackUnit.cpp:2339
TTrack::TLocationNameMultiMapIterator
TLocationNameMultiMap::iterator TLocationNameMultiMapIterator
Definition: TrackUnit.h:705
TRailGraphics::bm70CallingOn
Graphics::TBitmap * bm70CallingOn
Definition: GraphicUnit.h:465
TTrack::RebuildLocationNameMultiMap
void RebuildLocationNameMultiMap(int Caller)
Clears the existing LocationNameMultiMap and rebuilds it from TrackVector and InactiveTrackVector....
Definition: TrackUnit.cpp:9328
TOnePrefDir::EveryPrefDirMarker
void EveryPrefDirMarker(int Caller, TDisplay *Disp)
Similar to PrefDirMarker but used only to mark EveryPrefDir - red for unidirectional PrefDir & green ...
Definition: TrackUnit.cpp:12290
TRailGraphics::gl124
Graphics::TBitmap * gl124
Definition: GraphicUnit.h:589
TRailGraphics::bm32
Graphics::TBitmap * bm32
Definition: GraphicUnit.h:407
TRailGraphics::sm88
Graphics::TBitmap * sm88
Definition: GraphicUnit.h:862
TTrack::SetTrackFinished
void SetTrackFinished(bool Value)
Definition: TrackUnit.h:954
TTrack::GetInactiveTrackElementFromTrackMap
TTrackElement & GetInactiveTrackElementFromTrackMap(int Caller, int HLoc, int VLoc)
Return a reference to the inactive element at HLoc & VLoc, if no element is found an error is thrown.
Definition: TrackUnit.cpp:5684
TAllRoutes::LoadRoutes
bool LoadRoutes(int Caller, std::ifstream &InFile)
Loads the routes from a session file.
Definition: TrackUnit.cpp:18988
TRailGraphics::gl105
Graphics::TBitmap * gl105
Definition: GraphicUnit.h:568
TOneRoute::StartElement1
TPrefDirElement StartElement1
Definition: TrackUnit.h:1528
TRailGraphics::sm75
Graphics::TBitmap * sm75
Definition: GraphicUnit.h:911
TRailGraphics::sm115
Graphics::TBitmap * sm115
Definition: GraphicUnit.h:769
TOneRoute::ReqPosRouteID
IDInt ReqPosRouteID
session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1517
TRailGraphics::sm53
Graphics::TBitmap * sm53
Definition: GraphicUnit.h:828
TTrack::PlotRaisedLinkedLevelCrossingBarriers
void PlotRaisedLinkedLevelCrossingBarriers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot & close (to trains) all level crossings linked to TrackElement - always plots as red - auto.
Definition: TrackUnit.cpp:6891
TRailGraphics::bm71CallingOn
Graphics::TBitmap * bm71CallingOn
Definition: GraphicUnit.h:471
TTrack::LCFoundInRouteBuildingFlag
bool LCFoundInRouteBuildingFlag
true if a route set through an LC that is closed to trains (& therefore needs to be opened)
Definition: TrackUnit.h:761
TRailGraphics::DirectionSigRouteGraphicsPtr
Graphics::TBitmap * DirectionSigRouteGraphicsPtr[10]
preferred direction route marker arrows
Definition: GraphicUnit.h:1030
TRailGraphics::DirectionRouteAutoSigsGraphicsPtr
Graphics::TBitmap * DirectionRouteAutoSigsGraphicsPtr[10]
autosigs route marker arrows
Definition: GraphicUnit.h:1032
TRailGraphics::bm93set
Graphics::TBitmap * bm93set
Definition: GraphicUnit.h:514
TTrack::GetTrackVectorPositionFromString
int GetTrackVectorPositionFromString(int Caller, AnsiString String, bool GiveMessages)
Takes the ElementID value (an AnsiString) (e.g. "8-13", "N43-N127", etc) and returns the correspondin...
Definition: TrackUnit.cpp:7724
TOneRoute::TRouteFlash::PlotRouteOriginal
void PlotRouteOriginal(int Caller)
display the original (non route-coloured) graphic
Definition: TrackUnit.cpp:17429
TTrack::TTrackMapEntry
std::pair< THVPair, unsigned int > TTrackMapEntry
Definition: TrackUnit.h:673
TRailGraphics::bm37
Graphics::TBitmap * bm37
Definition: GraphicUnit.h:422
TTrack::ResetLevelCrossings
void ResetLevelCrossings(int Caller)
Set all LC attributes to 0 (closed to trains)
Definition: TrackUnit.cpp:7266
TRailGraphics::sm139
Graphics::TBitmap * sm139
Definition: GraphicUnit.h:785
Erase
@ Erase
Definition: TrackUnit.h:68
TRailGraphics::sm57
Graphics::TBitmap * sm57
Definition: GraphicUnit.h:832
TRailGraphics::bm29
Graphics::TBitmap * bm29
Definition: GraphicUnit.h:398
TRailGraphics::bm72grounddblwhite
Graphics::TBitmap * bm72grounddblwhite
Definition: GraphicUnit.h:480
TTrack::IsTrackLinked
bool IsTrackLinked(int Caller)
True if track has been successfully linked (not used any more)
Definition: TrackUnit.cpp:5305
TTrack::NewVector
TTrackVector NewVector
Definition: TrackUnit.h:815
TAllRoutes::LockedRouteTruncateTrackVectorPosition
unsigned int LockedRouteTruncateTrackVectorPosition
Definition: TrackUnit.h:1680
TUtilities::SaveFileDouble
void SaveFileDouble(std::ofstream &OutFile, double SaveDouble)
converts the double value to a string (if double stored directly it is truncated to 6 digits) then st...
Definition: Utilities.cpp:127
TRailGraphics::sm39
Graphics::TBitmap * sm39
Definition: GraphicUnit.h:812
TRailGraphics::sm85
Graphics::TBitmap * sm85
Definition: GraphicUnit.h:859
TRailGraphics::gl112
Graphics::TBitmap * gl112
Definition: GraphicUnit.h:576
TOnePrefDir::GetExactMatchFrom4MultiMap
TPrefDir4MultiMapIterator GetExactMatchFrom4MultiMap(int Caller, unsigned int PrefDirVectorPosition, bool &FoundFlag)
Retrieves a PrefDir4MultiMap iterator to the PrefDir element at PrefDirVectorPosition....
Definition: TrackUnit.cpp:13310
TTrack::TActiveLevelCrossing::TypeOfRoute
int TypeOfRoute
route type - 0 = nonsignals, 1 = preferred direction (can't have autosigs), 2 no route,...
Definition: TrackUnit.h:632
TTrack::GetAnyElementOppositeLinkPos
int GetAnyElementOppositeLinkPos(int Caller, int TrackVectorPosition, int LinkPos, bool &Derail)
Return the opposite link position for the element at TrackVectorPosition with link position LinkPos,...
Definition: TrackUnit.cpp:11004
Parapet
@ Parapet
Definition: TrackUnit.h:68
TRailGraphics::bm54
Graphics::TBitmap * bm54
Definition: GraphicUnit.h:448
TAllRoutes::GetFixedRouteAt
const TOneRoute & GetFixedRouteAt(int Caller, int At) const
Returns a constant reference to the route at AllRoutesVector position 'At', after performing range ch...
Definition: TrackUnit.cpp:17456
TUtilities::clTransparent
TColor clTransparent
the display background colour, can be white, black or dark blue
Definition: Utilities.h:65
TRailGraphics::sm14
Graphics::TBitmap * sm14
Definition: GraphicUnit.h:786
TRailGraphics::bmStraightEWSignalBlank
Graphics::TBitmap * bmStraightEWSignalBlank
Definition: GraphicUnit.h:994
TPrefDirElement::GetELinkPos
int GetELinkPos() const
Returns the ELink array position.
Definition: TrackUnit.h:287
TTrack::CheckLocationNameMultiMap
void CheckLocationNameMultiMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:8997
TOneRoute::TRouteFlash::PlotRouteOverlay
void PlotRouteOverlay(int Caller)
display the overlay (route-coloured) graphic
Definition: TrackUnit.cpp:17402
TRailGraphics::bm138
Graphics::TBitmap * bm138
Definition: GraphicUnit.h:378
TRailGraphics::sm79striped
Graphics::TBitmap * sm79striped
Definition: GraphicUnit.h:852
TTrack::InactiveTrackVector
TTrackVector InactiveTrackVector
Definition: TrackUnit.h:815
TAllRoutes::DecrementRouteElementNumbersInRoute2MultiMap
void DecrementRouteElementNumbersInRoute2MultiMap(int Caller, int RouteNumber, unsigned int ErasedElementNumber)
After a route element has been erased from the relevant PrefDirVector and from Route2MultiMap,...
Definition: TrackUnit.cpp:18322
TRailGraphics::gl126
Graphics::TBitmap * gl126
Definition: GraphicUnit.h:591
TRailGraphics::sm119
Graphics::TBitmap * sm119
Definition: GraphicUnit.h:916
TTrack::ActiveTrackElementNameMap
TActiveTrackElementNameMap ActiveTrackElementNameMap
map of active track element names
Definition: TrackUnit.h:790
TRailGraphics::sm138
Graphics::TBitmap * sm138
Definition: GraphicUnit.h:784
TTrackElement::HLoc
int HLoc
Definition: TrackUnit.h:148
TRailGraphics::bm72grounddblred
Graphics::TBitmap * bm72grounddblred
Definition: GraphicUnit.h:479
TRailGraphics::sm34
Graphics::TBitmap * sm34
Definition: GraphicUnit.h:807
TDisplay::PlotPointBlank
void PlotPointBlank(int Caller, int HLoc, int VLoc)
Definition: DisplayUnit.cpp:247
TRailGraphics::ConcourseStriped
Graphics::TBitmap * ConcourseStriped
Definition: GraphicUnit.h:550
TRailGraphics::PointModeGraphicsPtr
Graphics::TBitmap * PointModeGraphicsPtr[32][2]
for point fillets - 32 sets of points, each with two fillets
Definition: GraphicUnit.h:1035
TTrack::SigTableTwoAspect
TSigElement SigTableTwoAspect[40]
new at version 0.6 for two aspect
Definition: TrackUnit.h:738
TRailGraphics::sm27
Graphics::TBitmap * sm27
Definition: GraphicUnit.h:799
TTrainController::LogActionError
void LogActionError(int Caller, AnsiString HeadCode, AnsiString OtherHeadCode, TActionEventType ActionEventType, AnsiString LocationID)
Send an error message to the performance log and file, and as a warning if appropriate.
Definition: TrainUnit.cpp:14560
TRailGraphics::sm5
Graphics::TBitmap * sm5
Definition: GraphicUnit.h:824
TTrackElement::LCPlotted
bool LCPlotted
Utility marker to avoid plotting every element of a multitrack LC during ClearandRebuildRailway.
Definition: TrackUnit.h:138
TPrefDirElement::EXNumber
int EXNumber
used to facilitate identification of the appropriate preferred direction or route graphic
Definition: TrackUnit.h:220
TTrack::NumberOfPlatforms
int NumberOfPlatforms(int Caller, AnsiString LocationName)
Returns the number of separate platforms (not platform elements) at a given location,...
Definition: TrackUnit.cpp:11224
TOnePrefDir::PrefDirMarker
void PrefDirMarker(int Caller, TPrefDirRoute PrefDirRoute, bool BuildingPrefDir, TDisplay *Disp) const
PrefDir and route track marker, including direction markers.
Definition: TrackUnit.cpp:12217
TRailGraphics::bm78
Graphics::TBitmap * bm78
Definition: GraphicUnit.h:505
TTruncateReturnType
TTruncateReturnType
< a flag used during route truncation to indicate the nature of the selected element,...
Definition: TrackUnit.h:1290
TRailGraphics::bm75CallingOn
Graphics::TBitmap * bm75CallingOn
Definition: GraphicUnit.h:497
TOneRoute::SetLCChangeValues
void SetLCChangeValues(int Caller, bool PrefDirRoute)
After a route has been selected successfully this function sets all LC change values appropriately fo...
Definition: TrackUnit.cpp:17365
TRailGraphics::gl130
Graphics::TBitmap * gl130
Definition: GraphicUnit.h:597
TRailGraphics::bm71yellow
Graphics::TBitmap * bm71yellow
Definition: GraphicUnit.h:476
TRailGraphics::LCRHSVerMan
Graphics::TBitmap * LCRHSVerMan
Definition: GraphicUnit.h:732
TTrack
Definition: TrackUnit.h:562
TOnePrefDir::SearchLimitHighH
int SearchLimitHighH
Definition: TrackUnit.h:1349
TTrack::TwoAspectBuild
@ TwoAspectBuild
Definition: TrackUnit.h:862
TOnePrefDir::PrefDirVector
TPrefDirVector PrefDirVector
Definition: TrackUnit.h:1380
TAllRoutes::SetTrailingSignalsOnAutoSigsRoute
void SetTrailingSignalsOnAutoSigsRoute(int Caller, int TrackVectorPosition, int XLinkPos)
Enter with signal at TrackVectorElement already set to red by the passing train.
Definition: TrackUnit.cpp:18471
clB5G5R5
#define clB5G5R5
Definition: GraphicUnit.h:286
TUtilities::TimeStamp
AnsiString TimeStamp()
creates a string of the form 'hh:mm:ss' for use in call & event logging
Definition: Utilities.cpp:73
TAllRoutes::TLockedRouteClass::RouteNumber
int RouteNumber
the vector position number of the relevant route in AllRoutesVector
Definition: TrackUnit.h:1617
TTrack::ActiveMapCheck
bool ActiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:8025
TRailGraphics::gl2
Graphics::TBitmap * gl2
Definition: GraphicUnit.h:621
TTrack::Tag146Array
int Tag146Array[8][3]
Definition: TrackUnit.h:602
TRailGraphics::sm65
Graphics::TBitmap * sm65
Definition: GraphicUnit.h:841
TRailGraphics::gl47
Graphics::TBitmap * gl47
Definition: GraphicUnit.h:651
TRailGraphics::LCBothHorMan
Graphics::TBitmap * LCBothHorMan
Definition: GraphicUnit.h:727
TRailGraphics::sm78striped
Graphics::TBitmap * sm78striped
Definition: GraphicUnit.h:850
TTrackElement::ActiveTrackElementName
AnsiString ActiveTrackElementName
Location name used either in the timetable or for a continuation (continuation names not used in time...
Definition: TrackUnit.h:129
TRailGraphics::sm33
Graphics::TBitmap * sm33
Definition: GraphicUnit.h:806
TRailGraphics::bm94set
Graphics::TBitmap * bm94set
Definition: GraphicUnit.h:516
TRailGraphics::gl76Striped
Graphics::TBitmap * gl76Striped
Definition: GraphicUnit.h:686
TPrefDirElement::XLinkPos
int XLinkPos
exit link number & array position
Definition: TrackUnit.h:218
TAllRoutes::StoreOneRouteAfterSessionLoad
void StoreOneRouteAfterSessionLoad(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector after a session load....
Definition: TrackUnit.cpp:17962
TPrefDirElement::EntryDirectionGraphicPtr
Graphics::TBitmap * EntryDirectionGraphicPtr
pointers to the appropriate entry/exit graphic, or direction marker graphic, for preferred directions...
Definition: TrackUnit.h:226
TTrack::LoadTrack
void LoadTrack(int Caller, std::ifstream &VecFile, bool &GraphicsFollow)
Load track elements (active & inactive) from the file into the relevant vectors and maps,...
Definition: TrackUnit.cpp:2956
TRailGraphics::bm65
Graphics::TBitmap * bm65
Definition: GraphicUnit.h:451
TTrainController::LogEvent
void LogEvent(AnsiString Str)
store Str to the event log - moved from TUtilities for v0.6 so can record the tt clock value
Definition: TrainUnit.cpp:8751
TRailGraphics::sm74
Graphics::TBitmap * sm74
Definition: GraphicUnit.h:910
TTrack::PlotSignalPlatforms
void PlotSignalPlatforms(int Caller, int HLoc, int VLoc, TDisplay *Disp)
Plot platforms if any for a signal graphic - plotted before signal so shows through transparent signa...
Definition: TrackUnit.cpp:6082
TTrack::PlotAndAddTrackElement
void PlotAndAddTrackElement(int Caller, int CurrentTag, int Aspect, int HLocInput, int VLocInput, bool &TrackPlottedFlag, bool InternalChecks)
Called during track building or pasting, when an element identified by CurrentTag (i....
Definition: TrackUnit.cpp:2091
TUtilities::SaveFileString
void SaveFileString(std::ofstream &OutFile, AnsiString SaveString)
stores the string value to the file, then a '0' delimiter then a CR
Definition: Utilities.cpp:135
TTrack::Tag145Array
int Tag145Array[8][3]
Definition: TrackUnit.h:601
TRailGraphics::LCRHSVer
Graphics::TBitmap * LCRHSVer
Definition: GraphicUnit.h:725
TTrackElement::TwoAspect
@ TwoAspect
Definition: TrackUnit.h:159
TRailGraphics::sm76
Graphics::TBitmap * sm76
Definition: GraphicUnit.h:845
TTrack::GapFlashRed
TGraphicElement * GapFlashRed
the red & green circle graphics used to show where the gaps are
Definition: TrackUnit.h:798
TTrack::TryToConnectTrack
bool TryToConnectTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool GiveMessages)
Handles all tasks associated with track linking, returns true if successful (see also LinkTrack & Lin...
Definition: TrackUnit.cpp:2557
TPrefDirElement::ELinkPos
int ELinkPos
entry link number & array position
Definition: TrackUnit.h:216
TAllRoutes::TLockedRouteClass
Handles routes that are locked because of approaching trains.
Definition: TrackUnit.h:1615
TTrack::SetElementID
void SetElementID(int Caller, TTrackElement &TrackElement)
Convert the position values for the TrackElement into an identification string and load in ElementID.
Definition: TrackUnit.cpp:7688
TRailGraphics::bm72yellow
Graphics::TBitmap * bm72yellow
Definition: GraphicUnit.h:482
TOnePrefDir::EndPossible
bool EndPossible(int Caller, bool &LeadingPoints)
Used when setting preferred directions, true if able to finish at the last selected element (can't fi...
Definition: TrackUnit.cpp:12005
TOnePrefDir::ConsolidatePrefDirs
void ConsolidatePrefDirs(int Caller, TOnePrefDir *InputPrefDir)
Used when a preferred direction has been set to add all the elements to EveryPrefDir,...
Definition: TrackUnit.cpp:12783
TTrack::Tag131Array
int Tag131Array[4][3]
Definition: TrackUnit.h:600
TOneRoute::TRouteFlashElement::TrackVectorPosition
int TrackVectorPosition
element values
Definition: TrackUnit.h:1492
TTrack::RetrieveStripedNamedLocationGraphicsWhereRelevant
Graphics::TBitmap * RetrieveStripedNamedLocationGraphicsWhereRelevant(int Caller, TTrackElement TrackElement)
Return a pointer to the striped (i.e. when unnamed) graphic corresponding to TrackElement,...
Definition: TrackUnit.cpp:10353
TTrack::AddName
void AddName(int Caller, TTrackVectorIterator TrackElement, AnsiString Name)
TrackElement.LocationName becomes 'Name' (for active and inactive elements) and, if TrackElement is a...
Definition: TrackUnit.cpp:8389
IDInt
Definition: TrackUnit.h:511
TTrain::GetLeadElement
void GetLeadElement(int Caller)
Called when a train is about to leave an element and move onto another.
Definition: TrainUnit.cpp:2352
TRailGraphics::gl110
Graphics::TBitmap * gl110
Definition: GraphicUnit.h:574
TAllRoutes::GetModifiableRouteAtIDNumber
TOneRoute & GetModifiableRouteAtIDNumber(int Caller, IDInt RouteID)
Returns a modifiable reference to the route with ID number RouteID. If no route is found with that ID...
Definition: TrackUnit.cpp:18956
TRailGraphics::gl130Striped
Graphics::TBitmap * gl130Striped
Definition: GraphicUnit.h:598
TRailGraphics::sm133
Graphics::TBitmap * sm133
Definition: GraphicUnit.h:779
TTrack::FindAndHighlightAnUnsetGap
bool FindAndHighlightAnUnsetGap(int Caller)
True if there is an unset gap, and if so it is marked with a red circle, used during gap setting.
Definition: TrackUnit.cpp:4404
TDisplay
Definition: DisplayUnit.h:48
TTrack::PlotSmallRailway
void PlotSmallRailway(int Caller, TDisplay *Disp)
Plot on screen the zoomed-out railway.
Definition: TrackUnit.cpp:10103
TTrack::LinkTrackNoMessages
bool LinkTrackNoMessages(int Caller, bool FinalCall)
Attempt to link the track and return true if successful, don't issue any screen messages....
Definition: TrackUnit.cpp:5050
TTrackElement::ConnLinkPos
int ConnLinkPos[4]
Connecting element link position (i.e. array positions of the connecting element links,...
Definition: TrackUnit.h:146
TTrainController::ContinuationAutoSigVector
TContinuationAutoSigVector ContinuationAutoSigVector
vector for TContinuationAutoSigEntry objects
Definition: TrainUnit.h:816
TRailGraphics::sm129striped
Graphics::TBitmap * sm129striped
Definition: GraphicUnit.h:773
TRailGraphics::sm48
Graphics::TBitmap * sm48
Definition: GraphicUnit.h:822
TGraphicElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
original and temporary overlay graphics
Definition: TrackUnit.h:454
TAllRoutes::CheckForLoopingRoute
bool CheckForLoopingRoute(int Caller, int EndPosition, int EndXLinkPos, int StartPosition)
Functions defined in .cpp file.
Definition: TrackUnit.cpp:19053
TTrack::TTrack
TTrack()
Constructor, only one object of this class.
Definition: TrackUnit.cpp:1106
TTrack::FindNamedElementInLocationNameMultiMap
TLocationNameMultiMapIterator FindNamedElementInLocationNameMultiMap(int Caller, AnsiString LocationName, TTrackVectorIterator TrackElement, AnsiString &ErrorString)
Searches LocationNameMultiMap to check if the element pointed to by the TTrackVectorIterator has the ...
Definition: TrackUnit.cpp:9111
TTrackElement::operator==
bool operator==(TTrackElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:141
TTrack::GapHLoc
int GapHLoc
Definition: TrackUnit.h:584
TFixedTrackPiece::Config
TConfiguration Config[4]
the type of link - see TConfiguration above
Definition: TrackUnit.h:98
TTrack::CheckGapMap
void CheckGapMap(int Caller)
Validity test.
Definition: TrackUnit.cpp:7635
NotInRoute
@ NotInRoute
Definition: TrackUnit.h:1291
TDisplay::GetRectangle
void GetRectangle(int Caller, TRect DestRect, TRect SourceRect, Graphics::TBitmap *&OriginalGraphic)
Definition: DisplayUnit.cpp:227
TTrackElement::TrainIDOnElement
int TrainIDOnElement
Definition: TrackUnit.h:154
TRailGraphics::smRed
Graphics::TBitmap * smRed
Definition: GraphicUnit.h:887
TOnePrefDir::FindLinkingPrefDir
bool FindLinkingPrefDir(int Caller, int PrefDirVectorNumber, int LinkNumberPos, int LinkNumber, int &LinkedPrefDirVectorNumber)
Finds a pref dir element that links to another element at given vector number and link number & posit...
Definition: TrackUnit.cpp:13093
TTrack::FlipArray
int FlipArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'flipping' via menu items 'Edit' & 'Flip'
Definition: TrackUnit.h:776
TRailGraphics::LCPlainMan
Graphics::TBitmap * LCPlainMan
Definition: GraphicUnit.h:731
TRailGraphics::bm139
Graphics::TBitmap * bm139
Definition: GraphicUnit.h:381
TRailGraphics::gl3
Graphics::TBitmap * gl3
Definition: GraphicUnit.h:632
TPrefDirElement::CheckCount
int CheckCount
internal check value used when building preferred directions
Definition: TrackUnit.h:224
TRailGraphics::bm20
Graphics::TBitmap * bm20
Definition: GraphicUnit.h:393
TRailGraphics::sm77striped
Graphics::TBitmap * sm77striped
Definition: GraphicUnit.h:848
TOneRoute::GetPreferredRouteStartElement
bool GetPreferredRouteStartElement(int Caller, int HLoc, int VLoc, TOnePrefDir *EveryPrefDir, bool AutoSigsFlag)
Set the starting conditions for a preferred direction or automatic signal route selection beginning o...
Definition: TrackUnit.cpp:14114
TAllRoutes::RebuildRailwayFlag
bool RebuildRailwayFlag
this is set whenever a route has to be cancelled forcibly in order to force a ClearandRebuildRailway ...
Definition: TrackUnit.h:1685
TUtilities::LoadFileInt
int LoadFileInt(std::ifstream &InFile)
loads an int value from the file
Definition: Utilities.cpp:162
TTrack::SignalAspectBuildMode
enum TTrack::@2 SignalAspectBuildMode
aspect mode for future signal additions
TTrackElement::ElementID
AnsiString ElementID
the element identifier based on position in the railway
Definition: TrackUnit.h:131
TRailGraphics::sm112
Graphics::TBitmap * sm112
Definition: GraphicUnit.h:768
TTrack::CheckMapAndInactiveTrack
void CheckMapAndInactiveTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7603
TTrack::TActiveLevelCrossing::StartTime
TDateTime StartTime
stores the starting time for level crossing changing
Definition: TrackUnit.h:646
TRailGraphics::sm36
Graphics::TBitmap * sm36
Definition: GraphicUnit.h:809
TRailGraphics::sm136
Graphics::TBitmap * sm136
Definition: GraphicUnit.h:782
TRailGraphics::gl98
Graphics::TBitmap * gl98
Definition: GraphicUnit.h:716
TTrackElement::VLoc
int VLoc
The h & v locations in the railway (top lh corner of the first build screen = 0,0)
Definition: TrackUnit.h:148
TTrack::GetNonPointsOppositeLinkPos
int GetNonPointsOppositeLinkPos(int LinkPosIn)
Return the corresponding link position (track always occupies either links 0 & 1 or 2 & 3)
Definition: TrackUnit.h:897
TRailGraphics::sm100
Graphics::TBitmap * sm100
Definition: GraphicUnit.h:755
TOneRoute::TRouteFlash::RouteFlashVector
std::vector< TRouteFlashElement > RouteFlashVector
Definition: TrackUnit.h:1503
TRailGraphics::sm63
Graphics::TBitmap * sm63
Definition: GraphicUnit.h:839
TAllRoutes::TLockedRouteClass::LastTrackVectorPosition
unsigned int LastTrackVectorPosition
the TrackVector position of the last (i.e. most forward) element in the route
Definition: TrackUnit.h:1621
TRailGraphics::sm60
Graphics::TBitmap * sm60
Definition: GraphicUnit.h:836
TAllRoutes::NoRoute
@ NoRoute
Definition: TrackUnit.h:1631
TRailGraphics::bm42
Graphics::TBitmap * bm42
Definition: GraphicUnit.h:437
TTrack::RepositionAndMapTrack
bool RepositionAndMapTrack(int Caller)
When track is being built it is entered into the TrackVector in the order in which it is built,...
Definition: TrackUnit.cpp:4672
TRailGraphics::gl108
Graphics::TBitmap * gl108
Definition: GraphicUnit.h:571
TTrack::AdjNamedElement
bool AdjNamedElement(int Caller, int HLoc, int VLoc, int SpeedTag, AnsiString &LocationName, int &FoundElement)
Used in SearchForAndUpdateLocationName to check for adjacent named elements to a given element at HLo...
Definition: TrackUnit.cpp:8937
TTrainController::RestartTime
TDateTime RestartTime
TTClockTime when operation pauses ( = timetable start time prior to operation) TTClockTime is calcula...
Definition: TrainUnit.h:657
TOneRoute::ConvertAndAddPreferredRouteSearchVector
void ConvertAndAddPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID, bool AutoSigsFlag)
Called after a preferred (i.e. preferred direction or automatic signals) route has been selected and ...
Definition: TrackUnit.cpp:15301
TOnePrefDir::ClearPrefDir
void ClearPrefDir()
Empty the existing vectors & map.
Definition: TrackUnit.h:1319
TRailGraphics::gl99
Graphics::TBitmap * gl99
Definition: GraphicUnit.h:717
TGraphicElement::OverlayLoaded
bool OverlayLoaded
Definition: TrackUnit.h:448
TOnePrefDir::RealignAfterTrackErase
void RealignAfterTrackErase(int Caller, int ErasedTrackVectorPosition)
After a track element is erased the preferred direction elements are likely to be affected....
Definition: TrackUnit.cpp:13416
TRailGraphics::sm4
Graphics::TBitmap * sm4
Definition: GraphicUnit.h:813
PrefDirCall
@ PrefDirCall
Definition: TrackUnit.h:1297
TOnePrefDir::BiDirectionalPrefDir
bool BiDirectionalPrefDir(int Caller, TPrefDir4MultiMapIterator PDPtr)
Determines whether the preferred direction pointed to has another pref dir in the opposite direction ...
Definition: TrackUnit.cpp:13191
TTrackElement::StationEntryStopLinkPos1
int StationEntryStopLinkPos1
Definition: TrackUnit.h:152
Points
@ Points
Definition: TrackUnit.h:67
TRailGraphics::gl89unset
Graphics::TBitmap * gl89unset
Definition: GraphicUnit.h:703
TRailGraphics::LCPlain
Graphics::TBitmap * LCPlain
Definition: GraphicUnit.h:724
TAllRoutes::FindRoutePairFromRoute2MultiMap
TRouteElementPair FindRoutePairFromRoute2MultiMap(int Caller, int HLoc, int VLoc, int ELink, TRoute2MultiMapIterator &Route2MultiMapIterator)
Examines Route2MultiMap and returns a TRouteElementPair if one is found with the passed values of H,...
Definition: TrackUnit.cpp:18035
TRailGraphics::sm80
Graphics::TBitmap * sm80
Definition: GraphicUnit.h:854
TTrack::IsElementDefaultLength
bool IsElementDefaultLength(int Caller, TTrackElement &TrackElement, bool FirstTrack, bool &LengthDifferent, bool &SpeedDifferent)
Definition: TrackUnit.cpp:9786
TTrack::PopulateLCVector
void PopulateLCVector(int Caller)
Add all LCs to LCVector - note that this contains all LC elements whether linked to others or not.
Definition: TrackUnit.cpp:11075
TRailGraphics::bm33
Graphics::TBitmap * bm33
Definition: GraphicUnit.h:410
TRailGraphics::gl119
Graphics::TBitmap * gl119
Definition: GraphicUnit.h:583
TRailGraphics::sm47
Graphics::TBitmap * sm47
Definition: GraphicUnit.h:821
TRailGraphics::bm75grounddblred
Graphics::TBitmap * bm75grounddblred
Definition: GraphicUnit.h:499
TTrack::WriteOperatingTrackAndTextToImage
void WriteOperatingTrackAndTextToImage(int Caller, Graphics::TBitmap *Bitmap)
Called by TInterface::SaveOperatingImage1Click to add all track & text to the image file in their ope...
Definition: TrackUnit.cpp:4139
Trail
@ Trail
Definition: TrackUnit.h:77
TOneRoute::SetRouteSearchVectorGraphics
void SetRouteSearchVectorGraphics(int Caller, bool AutoSigsFlag, bool PrefDirRoute)
Set values for EXGraphicPtr and EntryDirectionGraphicPtr for all elements in SearchVector so that the...
Definition: TrackUnit.cpp:17314
TTrack::ChangeLocationNameMultiMapEntry
void ChangeLocationNameMultiMapEntry(int Caller, AnsiString NewName, TLocationNameMultiMapIterator SNIterator)
Changes the LocationName in the name multimap to NewName at the location pointed to by the TLocationN...
Definition: TrackUnit.cpp:9170
TOneRoute::SetRearwardsSignalsReturnFalseForTrain
bool SetRearwardsSignalsReturnFalseForTrain(int Caller, int &Attribute, int PrefDirVectorStartPosition) const
Called by TAllRoutes::SetAllRearwardsSignals to set rearwards signals from a specified starting posit...
Definition: TrackUnit.cpp:16899
TRailGraphics::sm107
Graphics::TBitmap * sm107
Definition: GraphicUnit.h:762
TGraphicElement::LoadOverlayGraphic
void LoadOverlayGraphic(int Caller, Graphics::TBitmap *Overlay)
Load the temporary overlay graphic.
Definition: TrackUnit.cpp:1830
TRailGraphics::bm75dblyellow
Graphics::TBitmap * bm75dblyellow
Definition: GraphicUnit.h:498
FailLockedRoute
@ FailLockedRoute
Definition: TrainUnit.h:40
TRailGraphics::sm32
Graphics::TBitmap * sm32
Definition: GraphicUnit.h:805
TOneRoute::SetRouteSignals
void SetRouteSignals(int Caller) const
Called when setting a route to set all points appropriately. Also called when a new train is added at...
Definition: TrackUnit.cpp:16717
TRailGraphics::sm44
Graphics::TBitmap * sm44
Definition: GraphicUnit.h:818
TRailGraphics::gl44
Graphics::TBitmap * gl44
Definition: GraphicUnit.h:648
TRailGraphics::bm36
Graphics::TBitmap * bm36
Definition: GraphicUnit.h:419
TRailGraphics::LCTopHor
Graphics::TBitmap * LCTopHor
Definition: GraphicUnit.h:726
Continuation
@ Continuation
Definition: TrackUnit.h:67
TRailGraphics::DirectionPrefDirGraphicsPtr
Graphics::TBitmap * DirectionPrefDirGraphicsPtr[10]
preferred direction marker arrows
Definition: GraphicUnit.h:1026
TUserGraphicItem::Height
int Height
Definition: DisplayUnit.h:35
TTrack::GetFilletGraphic
Graphics::TBitmap * GetFilletGraphic(int Caller, TTrackElement TrackElement)
Return a pointer to the point fillet (the bit that appears to move when points are changed) for the p...
Definition: TrackUnit.cpp:7482
GraphicUnit.h
THVPair
std::pair< int, int > THVPair
HLoc/VLoc position pair.
Definition: InterfaceUnit.h:49
TTrack::RebuildTrackAndText
void RebuildTrackAndText(int Caller, TDisplay *Disp, bool BothPointFilletsAndBasicLCs)
Called by TInterface::ClearandRebuildRailway to replot all the active and inactive track elements and...
Definition: TrackUnit.cpp:3719
TextUnit.h
TTrack::PlotPoints
void PlotPoints(int Caller, TTrackElement TrackElement, TDisplay *Disp, bool BothFillets)
Plot points on screen according to how they are set (Attribute value), or, with both fillets if BothF...
Definition: TrackUnit.cpp:5920
TDisplay::DisplayZoomOutOffsetV
static int DisplayZoomOutOffsetV
the verticalal offset of the zoomed-out display
Definition: DisplayUnit.h:86
TTrack::RightPlatAllowed
Set< int, 1, 146 > RightPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::bm12
Graphics::TBitmap * bm12
Definition: GraphicUnit.h:356
TTrack::DecrementValuesInInactiveTrackAndNameMaps
void DecrementValuesInInactiveTrackAndNameMaps(int Caller, unsigned int VecPos)
After an element has been erased from the InactiveTrackVector, all the later elements are moved down ...
Definition: TrackUnit.cpp:9217
TRailGraphics::sm8
Graphics::TBitmap * sm8
Definition: GraphicUnit.h:853
TRailGraphics::sm87
Graphics::TBitmap * sm87
Definition: GraphicUnit.h:861
AllRoutes
TAllRoutes * AllRoutes
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:54
TRailGraphics::sm94
Graphics::TBitmap * sm94
Definition: GraphicUnit.h:869
TOnePrefDir::ValidatePrefDir
bool ValidatePrefDir(int Caller)
Checks that all elements in PrefDirVector have been properly set, i.e. don't have their default value...
Definition: TrackUnit.cpp:12048
TTrack::LinkHVArray
int LinkHVArray[10][2]
array used to determine relative horizontal & vertical track element positions for specific link valu...
Definition: TrackUnit.h:590
TRailGraphics::sm49
Graphics::TBitmap * sm49
Definition: GraphicUnit.h:823
TRailGraphics::sm1
Graphics::TBitmap * sm1
Definition: GraphicUnit.h:753
TRailGraphics::sm84
Graphics::TBitmap * sm84
Definition: GraphicUnit.h:858
TGraphicElement::ScreenGraphicLoaded
bool ScreenGraphicLoaded
Definition: TrackUnit.h:448
TOneRoute::SearchForPreferredRoute
bool SearchForPreferredRoute(int Caller, TPrefDirElement PrefDirElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID, TOnePrefDir *EveryPrefDir, bool ConsecSignals, int EndSelectPosition, bool AutoSigsFlag)
Called by GetNextPreferredRouteElement to carry out the search for a valid route, and also called rec...
Definition: TrackUnit.cpp:14762
TTrack::TopPlatAllowed
Set< int, 1, 146 > TopPlatAllowed
Definition: TrackUnit.h:604
TRailGraphics::LinkPrefDirGraphicsPtr
Graphics::TBitmap * LinkPrefDirGraphicsPtr[30]
preferred direction graphic overlay
Definition: GraphicUnit.h:1015
TTrack::CheckTrackElementsInFile
bool CheckTrackElementsInFile(int Caller, int &NumberOfActiveElements, bool &GraphicsFollow, std::ifstream &VecFile)
True if TrackElements in the file are all valid.
Definition: TrackUnit.cpp:3336
TGraphicElement::Height
int Height
dimensions in pixels
Definition: TrackUnit.h:452
TRailGraphics::sm98
Graphics::TBitmap * sm98
Definition: GraphicUnit.h:874
TOneRoute::StartSelectionRouteID
IDInt StartSelectionRouteID
needed for session saves as routes in build are not saved in sessions
Definition: TrackUnit.h:1520
TFixedTrackPiece::SpeedTag
int SpeedTag
The element identification number - corresponds to the relevant SpeedButton->Tag.
Definition: TrackUnit.h:89
TRailGraphics::bm68green
Graphics::TBitmap * bm68green
Definition: GraphicUnit.h:456
TRailGraphics::gl79
Graphics::TBitmap * gl79
Definition: GraphicUnit.h:689
TTrain::Stopped
bool Stopped()
True if the train has stopped for any reason.
Definition: TrainUnit.h:624
TTrack::SigTableGroundSignal
TSigElement SigTableGroundSignal[40]
new at version 0.6 for ground signals
Definition: TrackUnit.h:740
TAllRoutes::LockedRouteLastXLinkPos
int LockedRouteLastXLinkPos
Definition: TrackUnit.h:1679
TRailGraphics::sm113
Graphics::TBitmap * sm113
Definition: GraphicUnit.h:912
TRailGraphics::bm135
Graphics::TBitmap * bm135
Definition: GraphicUnit.h:369
TPrefDirElement::GetELink
int GetELink() const
Returns ELink.
Definition: TrackUnit.h:281
TRailGraphics::LCBothVerMan
Graphics::TBitmap * LCBothVerMan
Definition: GraphicUnit.h:729
TUtilities::CheckFileDouble
bool CheckFileDouble(std::ifstream &InFile)
checks that the value is a double, returns true for success
Definition: Utilities.cpp:331
TRailGraphics::sm61
Graphics::TBitmap * sm61
Definition: GraphicUnit.h:837
TAllRoutes::DiagonalFouledByRouteOrTrain
bool DiagonalFouledByRouteOrTrain(int Caller, int HLoc, int VLoc, int DiagonalLinkNumber)
The track geometry allows diagonals to cross without occupying the same track element,...
Definition: TrackUnit.cpp:19135
TRailGraphics::bm73grounddblwhite
Graphics::TBitmap * bm73grounddblwhite
Definition: GraphicUnit.h:487
TOnePrefDir::CheckPrefDir4MultiMap
void CheckPrefDir4MultiMap(int Caller)
Diagnostic validity check.
Definition: TrackUnit.cpp:12988
TRailGraphics::BridgeSigRouteGraphicsPtr
Graphics::TBitmap * BridgeSigRouteGraphicsPtr[12]
route graphic for preferred routes overlay
Definition: GraphicUnit.h:1004
TRailGraphics::bm73dblyellow
Graphics::TBitmap * bm73dblyellow
Definition: GraphicUnit.h:485
TRailGraphics::sm111
Graphics::TBitmap * sm111
Definition: GraphicUnit.h:767
TOneRoute::TRouteFlashElement::OriginalGraphic
Graphics::TBitmap * OriginalGraphic
Definition: TrackUnit.h:1494
TRailGraphics::BridgeRouteAutoSigsGraphicsPtr
Graphics::TBitmap * BridgeRouteAutoSigsGraphicsPtr[12]
route graphic for automatic signal routes overlay
Definition: GraphicUnit.h:1008
TDisplay::DisplayZoomOutOffsetH
static int DisplayZoomOutOffsetH
the horizontal offset of the zoomed-out display
Definition: DisplayUnit.h:84
Display
TDisplay * Display
The object pointer for the on-screen display, object created in InterfaceUnit.
Definition: DisplayUnit.cpp:53
TRailGraphics::bm106
Graphics::TBitmap * bm106
Definition: GraphicUnit.h:350
TRailGraphics::bm56
Graphics::TBitmap * bm56
Definition: GraphicUnit.h:449
TTrack::RotRightArray
int RotRightArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating right' via menu items 'Edit' & 'Rotate right'
Definition: TrackUnit.h:782
TRailGraphics::gl146Striped
Graphics::TBitmap * gl146Striped
Definition: GraphicUnit.h:616
TTrack::GetVLocMin
int GetVLocMin()
Definition: TrackUnit.h:891
TTrack::ResetPoints
void ResetPoints(int Caller)
Called on exit from operation to reset all points to non-diverging or to left fork (Attribute = 0)
Definition: TrackUnit.cpp:4657
TRailGraphics::sm96striped
Graphics::TBitmap * sm96striped
Definition: GraphicUnit.h:872
TAllRoutes::StoreOneRoute
void StoreOneRoute(int Caller, TOneRoute *Route)
A new (empty apart from RouteID) TOneRoute is added to the AllRoutesVector.
Definition: TrackUnit.cpp:17933
TAllRoutes::AllRoutesSize
unsigned int AllRoutesSize() const
Returns the number of routes in the railway.
Definition: TrackUnit.h:1712
TTrack::DuplicatedLocationName
bool DuplicatedLocationName(int Caller, bool GiveMessage)
examines LocationNameMultiMap and returns true if there are two or more locations with the same name ...
Definition: TrackUnit.cpp:8527
TRailGraphics::gl87
Graphics::TBitmap * gl87
Definition: GraphicUnit.h:699
TTrack::THVPairsLinkedMap
std::map< THVPair, bool > THVPairsLinkedMap
added at v2.6.1 for use in PopulateHVPairsLinkedMapAndNoDuplicates
Definition: TrackUnit.h:709
TDisplay::Ellipse
void Ellipse(int Caller, int HPos, int VPos, TColor Col)
Plot an ellipse at the defined position and with the defined colour.
Definition: DisplayUnit.cpp:123
TRailGraphics::gl113
Graphics::TBitmap * gl113
Definition: GraphicUnit.h:577
TTrack::LCVector
TLCVector LCVector
vector of level crossing InactiveTrackVector positions
Definition: TrackUnit.h:802
TRailGraphics::gl49
Graphics::TBitmap * gl49
Definition: GraphicUnit.h:653
TUtilities::CheckFileBool
bool CheckFileBool(std::ifstream &InFile)
checks that the value is a bool returns true for success
Definition: Utilities.cpp:209
TTrack::OtherTrainOnTrack
bool OtherTrainOnTrack(int Caller, int NextPos, int NextEntryPos, int OwnTrainID)
True if another train on NextEntryPos track of element at NextPos, whether bridge or not,...
Definition: TrackUnit.cpp:10862
TRailGraphics::sm38
Graphics::TBitmap * sm38
Definition: GraphicUnit.h:811
TTrack::TActiveTrackElementNameMapEntry
std::pair< AnsiString, int > TActiveTrackElementNameMapEntry
Definition: TrackUnit.h:720
TOnePrefDir::SearchLimitHighV
int SearchLimitHighV
Definition: TrackUnit.h:1351
TAllRoutes::SaveRoutes
void SaveRoutes(int Caller, std::ofstream &OutFile)
Save railway route information to a session file or an error file.
Definition: TrackUnit.cpp:18972
TTrack::Tag77Array
int Tag77Array[25][3]
Definition: TrackUnit.h:594
TGraphicElement::PlotOverlay
void PlotOverlay(int Caller, TDisplay *Disp)
Plot the overlay graphic on screen.
Definition: TrackUnit.cpp:1840
TTrack::ResetSignals
void ResetSignals(int Caller)
Called on exit from operation to reset all signals to red (Attribute = 0)
Definition: TrackUnit.cpp:4642
Connection
@ Connection
Definition: TrackUnit.h:77
TTrack::LoadBarriersDownVector
void LoadBarriersDownVector(int Caller, std::ifstream &VecFile)
Load all BarriersDownVector values from SessionFile.
Definition: TrackUnit.cpp:3696
TRailGraphics::bm13
Graphics::TBitmap * bm13
Definition: GraphicUnit.h:359
TAllRoutes::RouteTruncateFlag
bool RouteTruncateFlag
used to flag the fact that a route is being truncated on order to change the behaviour of signal aspe...
Definition: TrackUnit.h:1687
TTrack::MarkOneLength
void MarkOneLength(int Caller, TTrackElement TE, bool FirstTrack, TDisplay *Disp)
Mark on screen a track element according to its length and speed limit if either of these differ from...
Definition: TrackUnit.cpp:9449
TRailGraphics::bmStraightNSSignalBlank
Graphics::TBitmap * bmStraightNSSignalBlank
Definition: GraphicUnit.h:995
TRailGraphics::LCTopHorMan
Graphics::TBitmap * LCTopHorMan
Definition: GraphicUnit.h:733
TRailGraphics::bm75green
Graphics::TBitmap * bm75green
Definition: GraphicUnit.h:501
TOneRoute::ConvertAndAddNonPreferredRouteSearchVector
void ConvertAndAddNonPreferredRouteSearchVector(int Caller, IDInt ReqPosRouteID)
Called after a non-preferred (i.e. unrestricted) route has been selected and has finished flashing,...
Definition: TrackUnit.cpp:16530
TOnePrefDir::ConvertPrefDirSearchVector
void ConvertPrefDirSearchVector(int Caller)
Called after a successful search to add the elements from the search vector to the pref dir vector.
Definition: TrackUnit.cpp:11866
TRailGraphics::gl91set
Graphics::TBitmap * gl91set
Definition: GraphicUnit.h:707
TRailGraphics::sm37
Graphics::TBitmap * sm37
Definition: GraphicUnit.h:810
TTrack::ElementInLNPendingList
bool ElementInLNPendingList(int Caller, int MapPos)
Definition: TrackUnit.cpp:8453
TRailGraphics::sm86
Graphics::TBitmap * sm86
Definition: GraphicUnit.h:860
TRailGraphics::LinkGraphicsPtr
Graphics::TBitmap * LinkGraphicsPtr[30]
basic single track graphic for use in plotting the original graphic during route flashing
Definition: GraphicUnit.h:1013
TAllRoutes::CheckMapAndRoutes
void CheckMapAndRoutes(int Caller)
Diagnostic function - checks equivalence for each route between entries in PrefDirVector and those in...
Definition: TrackUnit.cpp:18244
TAllRoutes::GetRouteElementDataFromRoute2MultiMap
TRouteElementPair GetRouteElementDataFromRoute2MultiMap(int Caller, int HLoc, int VLoc, TRouteElementPair &SecondPair)
Retrieve up to two TRouteElementPair entries from Route2MultiMap at H & V, the first as a function re...
Definition: TrackUnit.cpp:18200
DefaultTrackSpeedLimit
#define DefaultTrackSpeedLimit
Definition: TrackUnit.h:38
TTrack::PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers
void PlotPlainRaisedLinkedLevelCrossingBarriersAndSetMarkers(int Caller, int BaseElementSpeedTag, int HLoc, int VLoc, TDisplay *Disp)
Plot LC elements without any base elements, and set LCPlotted true - used in ClearandRebuildRailway.
Definition: TrackUnit.cpp:6964
TPrefDirElement::GetPrefDirGraphicPtr
Graphics::TBitmap * GetPrefDirGraphicPtr()
picks up the EXGraphicPtr for preferred directions
Definition: TrackUnit.cpp:541
TTrack::PlatformOnSignalSide
bool PlatformOnSignalSide(int Caller, int HLoc, int VLoc, int SpeedTag, Graphics::TBitmap *&SignalPlatformGraphic)
Check whether there is a platform present at HLoc & VLoc at the same side as the signal represented b...
Definition: TrackUnit.cpp:10733
TRailGraphics::gl80
Graphics::TBitmap * gl80
Definition: GraphicUnit.h:692
TRailGraphics::sm79
Graphics::TBitmap * sm79
Definition: GraphicUnit.h:851
TTrack::SigTable
TSigElement SigTable[40]
original table of signals for four aspect
Definition: TrackUnit.h:734
TOnePrefDir::TPrefDirVectorConstIterator
std::vector< TPrefDirElement >::const_iterator TPrefDirVectorConstIterator
Definition: TrackUnit.h:1378
TRailGraphics::smName
Graphics::TBitmap * smName
Definition: GraphicUnit.h:884
TRailGraphics::bm73grounddblred
Graphics::TBitmap * bm73grounddblred
Definition: GraphicUnit.h:486
TTrack::InactiveTrackElementPresentAtHV
bool InactiveTrackElementPresentAtHV(int Caller, int HLoc, int VLoc)
New at v1.2.0; true if an inactive track element present.
Definition: TrackUnit.cpp:5728
TRailGraphics::sm7
Graphics::TBitmap * sm7
Definition: GraphicUnit.h:844
TRailGraphics::gl91unset
Graphics::TBitmap * gl91unset
Definition: GraphicUnit.h:708
TRailGraphics::bm50
Graphics::TBitmap * bm50
Definition: GraphicUnit.h:445
TDisplay::PlotSignalBlank
void PlotSignalBlank(int Caller, int HLoc, int VLoc, int SpeedTag, bool RHSFlag)
Definition: DisplayUnit.cpp:261
TGraphicElement::OriginalLoaded
bool OriginalLoaded
Definition: TrackUnit.h:448
TTrack::OverrideAndHideSignalBridgeMessage
bool OverrideAndHideSignalBridgeMessage
if false signals facing bridges are not permitted, but can be set to true using CTRL ALT 5
Definition: TrackUnit.h:769
TTrack::SetStationEntryStopLinkPosses
void SetStationEntryStopLinkPosses(int Caller)
Called when trying to link track and when a name changed when track already linked.
Definition: TrackUnit.cpp:9909
TTrack::HLocMin
int HLocMin
Definition: TrackUnit.h:586
TTrack::SigTableThreeAspect
TSigElement SigTableThreeAspect[40]
new at version 0.6 for three aspect
Definition: TrackUnit.h:736
TTrack::CopyFlag
bool CopyFlag
true only when copying a selection, used to prevent location names being copied
Definition: TrackUnit.h:747
TAllRoutes::GetModifiableRouteAt
TOneRoute & GetModifiableRouteAt(int Caller, int At)
Returns a modifiable reference to the route at AllRoutesVector position 'At', after performing range ...
Definition: TrackUnit.cpp:17470
TTrack::LinkTrack
bool LinkTrack(int Caller, bool &LocError, int &HLoc, int &VLoc, bool FinalCall)
Attempt to link the track and return true if successful, if unsuccessful return error flag and positi...
Definition: TrackUnit.cpp:4782
TRailGraphics::sm16
Graphics::TBitmap * sm16
Definition: GraphicUnit.h:788
TTrack::ErrorInTrackBeforeSetGaps
bool ErrorInTrackBeforeSetGaps(int Caller, int &HLoc, int &VLoc)
Check for track errors prior to gap setting - disused as incorporated a time-consuming double brute f...
Definition: TrackUnit.cpp:2732
TRailGraphics::gl69
Graphics::TBitmap * gl69
Definition: GraphicUnit.h:675
TTrack::CheckMapAndTrack
void CheckMapAndTrack(int Caller)
Validity test.
Definition: TrackUnit.cpp:7563
TRailGraphics::bm140
Graphics::TBitmap * bm140
Definition: GraphicUnit.h:387
TTrack::LoadGraphics
void LoadGraphics(int Caller, std::ifstream &VecFile, UnicodeString GraphicsPath)
new at v2.4.0, load user graphics
Definition: TrackUnit.cpp:3098
TRailGraphics::bm137
Graphics::TBitmap * bm137
Definition: GraphicUnit.h:375
TRailGraphics::sm64
Graphics::TBitmap * sm64
Definition: GraphicUnit.h:840
TTrackElement::LocationName
AnsiString LocationName
location name not used for timetabling, only for identification: platforms, non-station named locatio...
Definition: TrackUnit.h:133
TRailGraphics::sm90
Graphics::TBitmap * sm90
Definition: GraphicUnit.h:865
TRailGraphics::bm136
Graphics::TBitmap * bm136
Definition: GraphicUnit.h:372
TOneRoute::SetRoutePoints
void SetRoutePoints(int Caller) const
Called when setting a route to set all points appropriately.
Definition: TrackUnit.cpp:16688
TTrack::TActiveLevelCrossing::HLoc
int HLoc
HLoc value for found level crossing element.
Definition: TrackUnit.h:642
TDisplay::DisplayOffsetH
static int DisplayOffsetH
the horizontal offset of the displayed screen
Definition: DisplayUnit.h:76
TOnePrefDir::PresetAutoRouteElementValid
bool PresetAutoRouteElementValid(int Caller, TPrefDirElement ElementIn, int EntryPos)
Checks ElementIn and returns true only if a single prefdir set at that H&V, with EntryPos giving entr...
Definition: TrackUnit.cpp:13680
TPrefDirElement::EntryExitNumber
bool EntryExitNumber()
determines and loads EXNumber (see above)
Definition: TrackUnit.cpp:293
TRailGraphics::bm101
Graphics::TBitmap * bm101
Definition: GraphicUnit.h:349
TTrack::SkipLocationNameMultiMapCheck
bool SkipLocationNameMultiMapCheck
changed from PastingWithAttributes in v2.4.0 as all pastes are now with attributes - needed to suppre...
Definition: TrackUnit.h:767
TRailGraphics::gl125
Graphics::TBitmap * gl125
Definition: GraphicUnit.h:590
TTrack::TLocationNameMultiMapRange
std::pair< TLocationNameMultiMapIterator, TLocationNameMultiMapIterator > TLocationNameMultiMapRange
Definition: TrackUnit.h:706
TRailGraphics::gl145Striped
Graphics::TBitmap * gl145Striped
Definition: GraphicUnit.h:614
TRailGraphics::bm27
Graphics::TBitmap * bm27
Definition: GraphicUnit.h:394
TRailGraphics::bm73yellow
Graphics::TBitmap * bm73yellow
Definition: GraphicUnit.h:489
InRouteTrue
@ InRouteTrue
Definition: TrackUnit.h:1291
TTrack::TUserGraphicMapEntry
std::pair< AnsiString, TPicture * > TUserGraphicMapEntry
an entry for TUserGraphicMap
Definition: TrackUnit.h:667
TRailGraphics::bm69yellow
Graphics::TBitmap * bm69yellow
Definition: GraphicUnit.h:463
TTrack::TGapMapIterator
TGapMap::iterator TGapMapIterator
the first gap HLoc/VLoc pair, contains one entry for each pair of matched gaps
Definition: TrackUnit.h:677
TRailGraphics::bmTransparentBgnd
Graphics::TBitmap * bmTransparentBgnd
Definition: GraphicUnit.h:900
TRailGraphics::gl23
Graphics::TBitmap * gl23
Definition: GraphicUnit.h:625
TOnePrefDir::GetNextPrefDirElement
bool GetNextPrefDirElement(int Caller, int HLoc, int VLoc, bool &FinishElement)
Used when continuing a chain of preferred directions or element lengths. Tries to find a set of linke...
Definition: TrackUnit.cpp:11426
TRailGraphics::bm68grounddblwhite
Graphics::TBitmap * bm68grounddblwhite
Definition: GraphicUnit.h:455
TGraphicElement::OverlayPlotted
bool OverlayPlotted
Definition: TrackUnit.h:448
TRailGraphics::bm93unset
Graphics::TBitmap * bm93unset
Definition: GraphicUnit.h:515
TRailGraphics::sm122
Graphics::TBitmap * sm122
Definition: GraphicUnit.h:919
TFixedTrackPiece::TrackType
TTrackType TrackType
the type of track element
Definition: TrackUnit.h:101
TOneRoute::TRouteFlashElement
A single flashing element of a route that flashes during setting.
Definition: TrackUnit.h:1490
TPrefDirElement
Basic preferred direction or route element - track element with additional members.
Definition: TrackUnit.h:213
TTrack::PopulateHVPairsLinkedMapAndNoDuplicates
bool PopulateHVPairsLinkedMapAndNoDuplicates(int Caller, TLocationNameMultiMapRange LNMMRg)
Used in checking for duplicate location names after Bill78 (discord name) developed the ....
Definition: TrackUnit.cpp:8576
TRailGraphics::sm26
Graphics::TBitmap * sm26
Definition: GraphicUnit.h:798
TGraphicElement::~TGraphicElement
~TGraphicElement()
Destructor.
Definition: TrackUnit.cpp:1738
TTrack::SearchForAndUpdateLocationName
void SearchForAndUpdateLocationName(int Caller, int HLoc, int VLoc, int SpeedTag)
Checks all locations that are adjacent to the one entered for linked named location elements.
Definition: TrackUnit.cpp:8758
TRailGraphics::gl24
Graphics::TBitmap * gl24
Definition: GraphicUnit.h:626
TRailGraphics::gl109
Graphics::TBitmap * gl109
Definition: GraphicUnit.h:572
TTrack::TSigElement
Used as basic elements in a table of signals - see SigTable below.
Definition: TrackUnit.h:724
TOnePrefDir::GetOnePrefDirPosition
int GetOnePrefDirPosition(int Caller, int HLoc, int VLoc)
Although there may be up to four entries at one H & V position this function gets just one....
Definition: TrackUnit.cpp:13387
TAllRoutes::GetFixedRouteAtIDNumber
const TOneRoute & GetFixedRouteAtIDNumber(int Caller, IDInt RouteID) const
Returns a constant reference to the route with ID number RouteID. If no route is found with that ID a...
Definition: TrackUnit.cpp:18940
TTrackElement::Attribute
int Attribute
special variable used only for points, signals & level crossings, ignored otherwise; points 0=set to ...
Definition: TrackUnit.h:142
TTrack::TBarrierState
TBarrierState
< state of barriers, values for level crossings either changing state or with barriers up or down
Definition: TrackUnit.h:624
TOnePrefDir::SearchLimitLowH
int SearchLimitLowH
Definition: TrackUnit.h:1348
TRailGraphics::SetUpAllDerivitiveGraphics
void SetUpAllDerivitiveGraphics(TColor TransparentColour)
Definition: GraphicUnit.cpp:4188
TTrack::LocationNameMultiMap
TLocationNameMultiMap LocationNameMultiMap
multimap of location names (see type for more information above)
Definition: TrackUnit.h:808
TTrack::NoNamedLocationElements
bool NoNamedLocationElements(int Caller)
True if there are no NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4533
TTrack::PlotSmallFlashingLinkedLevelCrossings
void PlotSmallFlashingLinkedLevelCrossings(int Caller, int HLoc, int VLoc, Graphics::TBitmap *GraphicPtr, TDisplay *Disp)
Plots either a LC or a blank element to flash manual LCs in zoomout mode.
Definition: TrackUnit.cpp:7426
TTrack::EraseTrackElement
void EraseTrackElement(int Caller, int HLocInput, int VLocInput, int &ErasedTrackVectorPosition, bool &TrackEraseSuccessfulFlag, bool InternalChecks)
Erases all active and inactive track elements at HLocInput & VLocInput from the vectors,...
Definition: TrackUnit.cpp:1935
TRailGraphics::bmRedEllipse
Graphics::TBitmap * bmRedEllipse
Definition: GraphicUnit.h:526
TRailGraphics::LinkRouteAutoSigsGraphicsPtr
Graphics::TBitmap * LinkRouteAutoSigsGraphicsPtr[30]
auto signal route graphic overlay
Definition: GraphicUnit.h:1021
TTrack::SetBarriersDownLCToManual
void SetBarriersDownLCToManual(int Caller, int HLoc, int VLoc)
Set TypeOfRoute value to 2 to indicate barriers manually closed.
Definition: TrackUnit.cpp:6228
TRailGraphics::bmDiagonalSignalBlank
Graphics::TBitmap * bmDiagonalSignalBlank
Definition: GraphicUnit.h:992
TRailGraphics::gl83
Graphics::TBitmap * gl83
Definition: GraphicUnit.h:695
FootCrossing
@ FootCrossing
Definition: TrackUnit.h:67
TRailGraphics::sm50
Graphics::TBitmap * sm50
Definition: GraphicUnit.h:825
TRailGraphics::gl25
Graphics::TBitmap * gl25
Definition: GraphicUnit.h:627
TTrack::IsLCAtHV
bool IsLCAtHV(int Caller, int HLoc, int VLoc)
True if a level crossing is found at H & V.
Definition: TrackUnit.cpp:7221
Platform
@ Platform
Definition: TrackUnit.h:67
TOnePrefDir::SearchVector
TPrefDirVector SearchVector
pref dir vectors, first is the main vector, second used to store search elements temporarily
Definition: TrackUnit.h:1380
TPrefDirElement::EXGraphicPtr
Graphics::TBitmap * EXGraphicPtr
Definition: TrackUnit.h:226
TTrack::TGapMapEntry
std::pair< THVPair, THVPair > TGapMapEntry
Definition: TrackUnit.h:679
TRailGraphics::sm95
Graphics::TBitmap * sm95
Definition: GraphicUnit.h:870
TTrack::LevelCrossingBarrierDownFlashDuration
float LevelCrossingBarrierDownFlashDuration
duration of the flash period when level crossing opening
Definition: TrackUnit.h:773
TTrainController::TTClockTime
TDateTime TTClockTime
the time indicated by the timetable clock
Definition: TrainUnit.h:653
TTrack::LocationsNotNamed
bool LocationsNotNamed(int Caller)
True if there are unnamed NamedLocationElements (includes footcrossings)
Definition: TrackUnit.cpp:4558
TTrack::RotLeftArray
int RotLeftArray[FirstUnusedSpeedTagNumber]
holds TrackElement SpeedTag values for 'rotating left' via menu items 'Edit' & 'Rotate left'
Definition: TrackUnit.h:784
TAllRoutes::TLockedRouteClass::LockStartTime
TDateTime LockStartTime
the timetable time at which the route is locked, to start the 2 minute clock
Definition: TrackUnit.h:1625
TRailGraphics::DirectionNonSigRouteGraphicsPtr
Graphics::TBitmap * DirectionNonSigRouteGraphicsPtr[10]
unrestricted route marker arrows
Definition: GraphicUnit.h:1028
TRailGraphics::sm11
Graphics::TBitmap * sm11
Definition: GraphicUnit.h:765
TRailGraphics::sm125
Graphics::TBitmap * sm125
Definition: GraphicUnit.h:922
TTrack::InactiveMapCheck
bool InactiveMapCheck(int Caller, int HLoc, int VLoc, int SpeedTag)
Used to check the validity of footcrossing links.
Definition: TrackUnit.cpp:7976
TRailGraphics::gl6
Graphics::TBitmap * gl6
Definition: GraphicUnit.h:665
TOnePrefDir
The basic preferred direction class, consisting of any number of elements with preferred directions s...
Definition: TrackUnit.h:1304
TRailGraphics::sm23
Graphics::TBitmap * sm23
Definition: GraphicUnit.h:795
TRailGraphics::sm55
Graphics::TBitmap * sm55
Definition: GraphicUnit.h:830
TTrack::NonFootCrossingNamedLocationExists
bool NonFootCrossingNamedLocationExists(int Caller)
True if there is a platform, NamedNonStationLocation or Concourse present in the railway.
Definition: TrackUnit.cpp:9366
TRailGraphics::BridgePrefDirGraphicsPtr
Graphics::TBitmap * BridgePrefDirGraphicsPtr[12]
preferred direction graphic overlay
Definition: GraphicUnit.h:1002
TRailGraphics::sm10
Graphics::TBitmap * sm10
Definition: GraphicUnit.h:754
TTrack::FindClosestLinkPosition
int FindClosestLinkPosition(int Caller, int StartTVPosition, int EndTVPosition)
Return the link array position for the element at StartTVPosition that gives the closest link to the ...
Definition: TrackUnit.cpp:10969
TGraphicElement::SetScreenHVSource
void SetScreenHVSource(int Caller, int HPosIn, int VPosIn)
Set HPos, VPos & SourceRect member values from the supplied positions.
Definition: TrackUnit.cpp:1745
TRailGraphics::sm41
Graphics::TBitmap * sm41
Definition: GraphicUnit.h:815
TUtilities::CallLog
std::deque< AnsiString > CallLog
call stack store, saved to the errorlog for diagnostic purposes
Definition: Utilities.h:55
TRailGraphics::gl22
Graphics::TBitmap * gl22
Definition: GraphicUnit.h:624
TOneRoute::TRouteFlashElement::HLoc
int HLoc
Definition: TrackUnit.h:1492
TRailGraphics::bm100
Graphics::TBitmap * bm100
Definition: GraphicUnit.h:348
TOneRoute::GetNextNonPreferredRouteElement
bool GetNextNonPreferredRouteElement(int Caller, int HLoc, int VLoc, bool Callon, IDInt &ReqPosRouteID, bool &PointsChanged)
Try to find a set of linked tracks between the route start element and the one at HLoc & VLoc....
Definition: TrackUnit.cpp:15722
TTrack::LCInSearchVector
bool LCInSearchVector(int Caller, int HLoc, int VLoc, TPrefDirVector SearchVector)
checks for a route being set across an LC to prevent barriers raising
Definition: TrackUnit.cpp:7409
TTrack::UserGraphicVector
TUserGraphicVector UserGraphicVector
Definition: TrackUnit.h:810
TTrackElement::Length23
int Length23
Definition: TrackUnit.h:150
TRailGraphics::sm134
Graphics::TBitmap * sm134
Definition: GraphicUnit.h:780
TUtilities::LoadFileBool
bool LoadFileBool(std::ifstream &InFile)
loads a bool value from the file
Definition: Utilities.cpp:145
TRailGraphics::gl71
Graphics::TBitmap * gl71
Definition: GraphicUnit.h:678
TOneRoute::TRouteFlashElement::OverlayGraphic
Graphics::TBitmap * OverlayGraphic
displayed alternately during flashing
Definition: TrackUnit.h:1494
TTrack::TActiveLevelCrossing
Definition: TrackUnit.h:629
TTrack::AnyLinkedBarrierDownVectorManual
bool AnyLinkedBarrierDownVectorManual(int Caller, int HLoc, int VLoc, int &BDVectorPos)
Checks BarrierDownVector and returns true if there is one that is linked to the LC at H & V positions...
Definition: TrackUnit.cpp:6245
TRailGraphics::gl92set
Graphics::TBitmap * gl92set
Definition: GraphicUnit.h:709
TTrack::SaveSessionBarriersDownVector
void SaveSessionBarriersDownVector(int Caller, std::ofstream &OutFile)
Save all vector values to the session file.
Definition: TrackUnit.cpp:3596
TRailGraphics::sm102
Graphics::TBitmap * sm102
Definition: GraphicUnit.h:757
TRailGraphics::gl4
Graphics::TBitmap * gl4
Definition: GraphicUnit.h:643
TDisplay::PlotAndAddUserGraphic
void PlotAndAddUserGraphic(int Caller, TUserGraphicItem UserGraphicItem)
Plot user graphic.
Definition: DisplayUnit.cpp:99
TDisplay::PlotSmallOutput
void PlotSmallOutput(int Caller, int HPos, int VPos, Graphics::TBitmap *PlotItem)
Plot small (4x4) graphic PlotItem on the zoomed-out display at HPos & Vpos.
Definition: DisplayUnit.cpp:113
TTrack::Tag96Array
int Tag96Array[28][3]
Definition: TrackUnit.h:597
TRailGraphics::sm15
Graphics::TBitmap * sm15
Definition: GraphicUnit.h:787
TTrack::LCChangeFlag
bool LCChangeFlag
true when LCs changing
Definition: TrackUnit.h:753
TTrack::SelectVectorAt
TTrackElement & SelectVectorAt(int Caller, int At)
A range-checked version of SelectVector.at(At)
Definition: TrackUnit.cpp:10895
TRailGraphics::sm13
Graphics::TBitmap * sm13
Definition: GraphicUnit.h:774
TRailGraphics::sm91
Graphics::TBitmap * sm91
Definition: GraphicUnit.h:866
TRailGraphics::sm59
Graphics::TBitmap * sm59
Definition: GraphicUnit.h:834
TTrackElement::SpeedLimit23
int SpeedLimit23
Element lengths and speed limits, ...01 is for the track with link positions [0] and [1],...
Definition: TrackUnit.h:150
TTrack::TLNPendingListIterator
TLNPendingList::iterator TLNPendingListIterator
naming of linked named location elements
Definition: TrackUnit.h:693
TRailGraphics::sm114
Graphics::TBitmap * sm114
Definition: GraphicUnit.h:913
TPrefDirElement::LogPrefDir
AnsiString LogPrefDir() const
Sends a list of PrefDirElement values to Utilities->CallLog file for debugging purposes.
Definition: TrackUnit.cpp:279
TRailGraphics::gl82
Graphics::TBitmap * gl82
Definition: GraphicUnit.h:694
TTrack::TActiveLevelCrossing::ChangeDuration
float ChangeDuration
duration of the level crossing changing period
Definition: TrackUnit.h:638
TRailGraphics::gl95set
Graphics::TBitmap * gl95set
Definition: GraphicUnit.h:713
TDisplay::DisplayOffsetVHome
static int DisplayOffsetVHome
the vertical offset of the 'Home' display
Definition: DisplayUnit.h:82
TPrefDirElement::operator==
bool operator==(TPrefDirElement RHElement)
equivalence operator
Definition: TrackUnit.cpp:1054
TrainUnit.h
TRailGraphics::bm34
Graphics::TBitmap * bm34
Definition: GraphicUnit.h:413
TRailGraphics::gl104
Graphics::TBitmap * gl104
Definition: GraphicUnit.h:567
TFixedTrackPiece::Link
int Link[4]
Track connection link values, max. of 4, unused = -1, top lh diag.=1, top=2, top rh diag....
Definition: TrackUnit.h:91
TOneRoute::SearchForNonPreferredRoute
bool SearchForNonPreferredRoute(int Caller, TTrackElement CurrentTrackElement, int XLinkPos, int RequiredPosition, IDInt ReqPosRouteID)
Called by GetNextNonPreferredRouteElement to carry out the search for linked track,...
Definition: TrackUnit.cpp:16096
TTrack::TLNDone2MultiMapEntry
std::pair< THVPair, int > TLNDone2MultiMapEntry
can be up to 2 entries (platforms) at a single location
Definition: TrackUnit.h:700
TTrack::TrackMap
TTrackMap TrackMap
map of track (see type for more information above)
Definition: TrackUnit.h:813
RouteCall
@ RouteCall
Definition: TrackUnit.h:1297
TRailGraphics::bm141
Graphics::TBitmap * bm141
Definition: GraphicUnit.h:388
TOnePrefDir::GetFixedSearchElementAt
const TPrefDirElement & GetFixedSearchElementAt(int Caller, int At) const
Return a non-modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11360
TRailGraphics::sm76striped
Graphics::TBitmap * sm76striped
Definition: GraphicUnit.h:846
TTextHandler::TextErase
bool TextErase(int Caller, int HPosition, int VPosition, AnsiString TextToErase)
look for a text item in the vicinity of HPosInput & VPosInput & if TextToErase is null then erase any...
Definition: TextUnit.cpp:265
TRailGraphics::gl127
Graphics::TBitmap * gl127
Definition: GraphicUnit.h:592
TRailGraphics::bm75yellow
Graphics::TBitmap * bm75yellow
Definition: GraphicUnit.h:502
NotSet
@ NotSet
Definition: TrackUnit.h:77
TTrack::TInactiveTrack2MultiMapIterator
TInactiveTrack2MultiMap::iterator TInactiveTrack2MultiMapIterator
iterator for TInactiveTrack2MultiMap
Definition: TrackUnit.h:683
TAllRoutes::SetTrailingSignalsOnContinuationRoute
void SetTrailingSignalsOnContinuationRoute(int Caller, int RouteNumber, int AccessNumber)
This is called by the InterfaceUnit at intervals based on entries in the ContinuationAutoSigVector in...
Definition: TrackUnit.cpp:18516
TDisplay::DisplayZoomOutOffsetHHome
static int DisplayZoomOutOffsetHHome
the horizontal offset of the zoomed-out 'Home' display
Definition: DisplayUnit.h:88
TMapComp::operator()
bool operator()(const THVPair &lower, const THVPair &higher) const
HLoc VLoc.
Definition: TrackUnit.cpp:241
TRailGraphics::bm16
Graphics::TBitmap * bm16
Definition: GraphicUnit.h:391
TRailGraphics::gl128
Graphics::TBitmap * gl128
Definition: GraphicUnit.h:593
TRailGraphics::gl116
Graphics::TBitmap * gl116
Definition: GraphicUnit.h:580
TTrack::FindHighestLowestAndLeftmostNamedElements
bool FindHighestLowestAndLeftmostNamedElements(int Caller, AnsiString Name, int &VPosHi, int &VPosLo, int &HPos)
Used in locating the screen name position for a named location, return true if find an inactive eleme...
Definition: TrackUnit.cpp:10924
TTrack::TrackClear
void TrackClear(int Caller)
Empty the track and inactive track vectors, the corresponding track maps, and LocationNameMultiMap.
Definition: TrackUnit.cpp:10185
TTrack::TIMPair
std::pair< unsigned int, unsigned int > TIMPair
TrackElement pair type used for inactive elements, values are vector positions.
Definition: TrackUnit.h:688
TTextHandler::TextVectorSize
unsigned int TextVectorSize(int Caller)
return the number of items in TextVector
Definition: TextUnit.cpp:533
TPrefDirElement::ELink
int ELink
Definition: TrackUnit.h:216
TRailGraphics::sm130striped
Graphics::TBitmap * sm130striped
Definition: GraphicUnit.h:776
TRailGraphics::sm118
Graphics::TBitmap * sm118
Definition: GraphicUnit.h:915
TTrack::SetLinkedLevelCrossingBarrierAttributes
void SetLinkedLevelCrossingBarrierAttributes(int Caller, int HLoc, int VLoc, int Attr)
Set linked LC attributes; 0=closed to trains, 1 = open to trains, 2 = changing state = closed to trai...
Definition: TrackUnit.cpp:6146
TTrackElement::GroundSignal
@ GroundSignal
Definition: TrackUnit.h:159
LevelCrossing
@ LevelCrossing
Definition: TrackUnit.h:68
TRailGraphics::sm126
Graphics::TBitmap * sm126
Definition: GraphicUnit.h:923
TTrack::ActiveTrackElementNameMapCompiledFlag
bool ActiveTrackElementNameMapCompiledFlag
indicates that the ActiveTrackElementNameMap has been compiled
Definition: TrackUnit.h:745
TOnePrefDir::GetModifiableSearchElementAt
TPrefDirElement & GetModifiableSearchElementAt(int Caller, int At)
Return a modifiable element at SearchVector position 'At'.
Definition: TrackUnit.cpp:11372
TOnePrefDir::TotalSearchCount
int TotalSearchCount
counts search elements, used to abort searches (prefdirs or routes) if reaches too high a value
Definition: TrackUnit.h:1353
Track
TTrack * Track
the object pointer, object created in InterfaceUnit
Definition: TrackUnit.cpp:53
TRailGraphics::bm18
Graphics::TBitmap * bm18
Definition: GraphicUnit.h:392
TTrackElement::Conn
int Conn[4]
Connecting element position in TrackVector, set to -1 if no connecting link or if track not linked.
Definition: TrackUnit.h:144
TTrack::~TTrack
~TTrack()
Destructor.
Definition: TrackUnit.cpp:1510
TRailGraphics::sm62
Graphics::TBitmap * sm62
Definition: GraphicUnit.h:838
TRailGraphics::LCBothVer
Graphics::TBitmap * LCBothVer
Definition: GraphicUnit.h:722
TRailGraphics::sm35
Graphics::TBitmap * sm35
Definition: GraphicUnit.h:808
RailGraphics
TRailGraphics * RailGraphics
the object pointer, object created in InterfaceUnit
Definition: GraphicUnit.cpp:50
TRailGraphics::gl81
Graphics::TBitmap * gl81
Definition: GraphicUnit.h:693
TTrack::HLocMax
int HLocMax
Definition: TrackUnit.h:586
TRailGraphics::gl146
Graphics::TBitmap * gl146
Definition: GraphicUnit.h:615
TTrack::PlotSmallRedGap
void PlotSmallRedGap(int Caller)
Plot on screen in zoomed-out mode and in gap setting mode a small red square corresponding to the gap...
Definition: TrackUnit.cpp:10176
Bridge
@ Bridge
Definition: TrackUnit.h:67
TRailGraphics::sm78
Graphics::TBitmap * sm78
Definition: GraphicUnit.h:849
TRailGraphics::bm43
Graphics::TBitmap * bm43
Definition: GraphicUnit.h:440
InRouteFalse
@ InRouteFalse
Definition: TrackUnit.h:1291
TRailGraphics::sm25
Graphics::TBitmap * sm25
Definition: GraphicUnit.h:797
TRailGraphics::bmName
Graphics::TBitmap * bmName
Definition: GraphicUnit.h:524
Gap
@ Gap
Definition: TrackUnit.h:77
Buffers
@ Buffers
Definition: TrackUnit.h:67
TOneRoute::SetRemainingSearchVectorValues
void SetRemainingSearchVectorValues(int Caller)
Called when setting unrestricted routes to set the route element values appropriately after a success...
Definition: TrackUnit.cpp:16446
TRailGraphics::gl79Striped
Graphics::TBitmap * gl79Striped
Definition: GraphicUnit.h:690
TUtilities::ScreenElementHeight
int ScreenElementHeight
height of display screen in elements
Definition: Utilities.h:50
CrossConn
@ CrossConn
Definition: TrackUnit.h:77
TOnePrefDir::GetPrefDirStartElement
bool GetPrefDirStartElement(int Caller, int HLoc, int VLoc)
Used when beginning a chain of preferred directions or element lengths. Enter with HLoc & VLoc set to...
Definition: TrackUnit.cpp:11384
TRailGraphics::bm71grounddblwhite
Graphics::TBitmap * bm71grounddblwhite
Definition: GraphicUnit.h:474
TTrack::GapsUnset
bool GapsUnset(int Caller)
True if there are gaps in the railway and any are unset.
Definition: TrackUnit.cpp:4470
TOnePrefDir::LastElementNumber
int LastElementNumber(int Caller) const
Return the vector position of the last element in the vector (i.e. one less than the vector size)
Definition: TrackUnit.cpp:11307
TRailGraphics::sm58
Graphics::TBitmap * sm58
Definition: GraphicUnit.h:833